0
点赞
收藏
分享

微信扫一扫

asyne,await,task.wait,task.result用法


asyne,await,task.wait,task.result用法



首先看下面的代码:


class Program
{
static void Main(string[] args)
{
TestTask();
}
}


private async void TestTask()
{
Console.WriteLine("step1,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);


AsyncDemo demo = new AsyncDemo();
//var result = demo.AsyncSleep().Result;//.Result会阻塞当前线程直到AsyncSleep返回
//demo.AsyncSleep().Wait();//Wait会阻塞当前线程直到AsyncSleep返回
//Console.WriteLine(result);
demo.AsyncSleep();//不会阻塞当前线程

Console.WriteLine("step5,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
Console.ReadLine();
}

public class AsyncDemo
{
public async Task<string> AsyncSleep()
{
Console.WriteLine("step2,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);


//await关键字表示“等待”Task.Run传入的逻辑执行完毕,此时(等待时)AsyncSleep的调用方能继续往下执行(准确地说,是当前线程不会被阻塞)
//Task.Run将开辟一个新线程执行指定逻辑
var result = "";
//result = await Task.Run(() => Sleep(10)).ConfigureAwait(false);
await Task.Run(() => Sleep(10));
Console.WriteLine("step4,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);


return result;
}


private string Sleep(int second)
{
Console.WriteLine("step3,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);


Thread.Sleep(second * 1000);
return "sleep";
}
}


运行结果:


step1,


step2,


step3,


step5,


step4,




修改下代码如下:


private async void TestTask()
{
Console.WriteLine("step1,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);


AsyncDemo demo = new AsyncDemo();
//var result = demo.AsyncSleep().Result;//Result会阻塞当前线程直到AsyncSleep返回
demo.AsyncSleep().Wait(); //Wait会阻塞当前线程直到AsyncSleep返回
//Console.WriteLine(result);
//demo.AsyncSleep();//不会阻塞当前线程

Console.WriteLine("step5,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
Console.ReadLine();
}

public class AsyncDemo
{
public async Task<string> AsyncSleep()
{
Console.WriteLine("step2,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);


//await关键字表示“等待”Task.Run传入的逻辑执行完毕,此时(等待时)AsyncSleep的调用方能继续往下执行(准确地说,是当前线程不会被阻塞)
//Task.Run将开辟一个新线程执行指定逻辑
var result = "";
//result = await Task.Run(() => Sleep(10)).ConfigureAwait(false);
await Task.Run(() => Sleep(10));
Console.WriteLine("step4,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);

return result;
}

private string Sleep(int second)
{
Console.WriteLine("step3,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);


Thread.Sleep(second * 1000);
return "sleep";
}
}


运行结果如下:


step1,


step2,


step3,



step4,step5出不来了,程序死锁



再修改下代码如下:


private async void TestTask()
{
Console.WriteLine("step1,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);


AsyncDemo demo = new AsyncDemo();
//var result = demo.AsyncSleep().Result;//Result会阻塞当前线程直到AsyncSleep返回
demo.AsyncSleep().Wait(); //Wait会阻塞当前线程直到AsyncSleep返回
//Console.WriteLine(result);
//demo.AsyncSleep();//不会阻塞当前线程

Console.WriteLine("step5,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
Console.ReadLine();
}
public class AsyncDemo
{
public async Task<string> AsyncSleep()
{
Console.WriteLine("step2,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);


//await关键字表示“等待”Task.Run传入的逻辑执行完毕,此时(等待时)AsyncSleep的调用方能继续往下执行(准确地说,是当前线程不会被阻塞)
//Task.Run将开辟一个新线程执行指定逻辑
var result = "";
result = await Task.Run(() => Sleep(10)).ConfigureAwait(false);
//await Task.Run(() => Sleep(10));
Console.WriteLine("step4,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);


return result;
}


private string Sleep(int second)
{
Console.WriteLine("step3,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);


Thread.Sleep(second * 1000);
return "sleep";
}
}

      


运行结果:


step1,


step2,


step3,


step4,


step5,




代码再修改如下:


private async void TestTask()
{
Console.WriteLine("step1,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);


AsyncDemo demo = new AsyncDemo();
var result = demo.AsyncSleep().Result;//Result会阻塞当前线程直到AsyncSleep返回
//demo.AsyncSleep().Wait(); //Wait会阻塞当前线程直到AsyncSleep返回
//Console.WriteLine(result);
//demo.AsyncSleep();//不会阻塞当前线程

Console.WriteLine("step5,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
Console.ReadLine();
}
public class AsyncDemo
{
public async Task<string> AsyncSleep()
{
Console.WriteLine("step2,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);


//await关键字表示“等待”Task.Run传入的逻辑执行完毕,此时(等待时)AsyncSleep的调用方能继续往下执行(准确地说,是当前线程不会被阻塞)
//Task.Run将开辟一个新线程执行指定逻辑
var result = "";
result = await Task.Run(() => Sleep(10)).ConfigureAwait(false);
//await Task.Run(() => Sleep(10));
Console.WriteLine("step4,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);


return result;
}


private string Sleep(int second)
{
Console.WriteLine("step3,线程ID:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);


Thread.Sleep(second * 1000);
return "sleep";
}
}


运行结果:


step1,


step2,


step3,


step4,


step5,



所在当用 .Wait()或者.Result 调用async方法时,如果async方法内有 await 调用其它方法时,会产生死锁,可以用await Task.Run(() => Sleep(10)).ConfigureAwait(false);


即加上.ConfigureAwait(false),可以解决死锁问题


所以推荐的用法是当需要等待结果里 用 await 方式调用。


 .ConfigureAwait

尝试将延续任务封送回原始上下文,则为 true;否则为 false。



对ConfigureAwait的了解:



1)当ConfigureAwait(true),代码由同步执行进入异步执行时,当前同步执行的线程上下文信息(比如HttpConext.Current,Thread.CurrentThread.CurrentCulture)就会被捕获并保存至SynchronizationContext中,供异步执行中使用,并且供异步执行完成之后(await之后的代码)的同步执行中使用(虽然await之后是同步执行的,但是发生了线程切换,会在另外一个线程中执行「

ASP.NET场景」)。这个捕获当然是有代价的,当时我们误以为性能问题是这个地方的开销引起,但实际上这个开销很小,在我们的应用场景不至于会带来性能问题。


2)当Configurewait(flase),则不进行线程上下文信息的捕获,async方法中与await之后的代码执行时就无法获取await之前的线程的上下文信息,在

ASP.NET中最直接的影响就是HttpConext.Current的值为null。 





​​ https://msdn.microsoft.com/zh-cn/magazine/jj991977.aspx  ​​



--- end ---

举报

相关推荐

0 条评论