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。
参考: http://www.cnblogs.com/newton/archive/2013/05/13/3075039.html
https://msdn.microsoft.com/zh-cn/magazine/jj991977.aspx
--- end ---