首先大概介绍下async
和await
这两个关键字。
在.Net 4.5中,微软为了方便异步编程提供了async
和await
这两个关键字,使用他们,可以使我们很方便的实现自己的异步代码,而不用太去关心其内部原理。那么他们的主要作用使什么呢?
async
关键字加在方法的声明上,他的主要目的使为了使方法内部的await
关键字生效。而方法的返回值也一般是Task
或者Task<T>
类型。这些Task
类型一般相当于是future
,用来在异步方法结束时通知主程序。如下面示例代码:
public async Task DoSomethingAsync()
{
int val = 1;
await Task.Delay(TimeSpan.FromSeconds(1));
val *= 3;
await Task.Delay(TimeSpan.FromSeconds(2));
Console.WriteLine(val);
}
和同步方法一样,async
方法在开始时候以同步方式执行。在async
方法内部,await
关键字对他对参数执行了一个异步等待,他首先检查操作是否已经完成,如果完成了,则继续执行。否则,他会暂停async
方法,并返回,留下一个未完成的task
。一段时间操作完成后,async
方法恢复执行。
当异步方法在await
处暂停时,就可以捕捉上下文。如果当前SynchronizationContext
不为空,这个上下文就是当前SynchronizationContext
,如果当前SynchronizationContext
为空,则这个上下文为当前TaskScheduler
。该方法会在这个上下文中继续运行。一般情况下,运行UI线程时采用UI上下文,处理Asp.Net请求时使用Asp.Net请求上下文,其他很多情况下采用线程池上下文。
再看看下面这段代码:
public ActionResult TestDeadLock()
{
var result = DoSomethingAsync().GetAwaiter().GetResult();
return Content(result);
}
public async Task<string> DoSomethingAsync()
{
await Task.Delay(TimeSpan.FromSeconds(1));
return "success";
}
如果DoSomethingAsync
方法在UI或Asp.Net的上下文中调用,就会发生死锁。这是因为这两中上下文每次只能执行一个线程,当TestDeadLock
调用DoSomethingAsync
方法时,DoSomethingAsync
开始执行Delay
语句,然后TestDeadLock
会同步的等待DoSomethingAsync
方法执行完成,同时会阻塞上下文线程,当Delay
语句执行完之后,await
会尝试在已捕获的上下文中继续运行DoSomethingAsync
方法,但这个时候无法成功,因为上下文中已经有了一个阻塞的线程,并且这个上下文只允许同时运行一个线程。这里有一种方式可以避免死锁:在DoSomethingAsync
中使用ConfigureAwait(false)
,但是这样会导致await
忽略该方法的上下文。
如下面这段代码:
public async Task<string> DoSomethingAsync()
{
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
var request = System.Web.HttpContext.Current.Request;
return request.HttpMethod;
}
这个时候调用DoSomethingAsync
方法不会产生死锁,因为我们使用ConfigureAwait(false)
来忽略上下文,但是下面这段代码var request = System.Web.HttpContext.Current.Request
会产生空引用异常,因为在Asp.Net中,忽略上下文会导致System.Web.HttpContext.Current
的值为Null
。
要避免这些错误,一个时尽量异步到底,另外就是尽量避免在Asp.Net中使用System.Web.HttpContext.Current
。
<h3 id="_1">测试</h3>
测试1 >测试2
测试3
python {.line-numbers} print('你好') print('你好') print('你好') print('你好') print('你好')
<div class="codehilite">
</div>test11~~
test
test
测试
测试测试。
测试
你好
>天真好
python {.line-numbers} print('你好')