在asp.net mvc中使用async的时候遇到一个问题,请教下大家。下面是示例,
public class HomeController : Controller { public ActionResult Index() { TestTask(); return View(); } private async Task TestTask() { try { WebRequest request = WebRequest.CreateHttp("http://localhost:4113/");//这个页面请求需要消耗5秒时间 request.Method = "Get"; var response = await request.GetResponseAsync().ConfigureAwait(true); Debug.Write("异步外面执行"); } catch (Exception ex) { throw; } } }
我的目的是这样的,当页面执行index controller的时候会异步去访问一个远程页面(这个页面获取需要5秒钟),然后此时在这个异步还未结束的时候,index已经执行完毕,页面也已经展示出来。
接着过了几秒钟,远程访问的异步执行结束了,按照我的设计,根据这句代码 xxx.ConfigureAwait(true),目的是想让异步结束后,在返回到之前的上下文(http 线程),继续执行,所以在这句Debug.Write代码里面打了断点看看能否执行下去,但是发现断点根本没有进来,我以为是之前的上下文已经不存在,无法获取,应该抛出异常,然后我又在异常里面打了断点,依然没有进入。
问题描述完了,不知道有没有园友能帮忙解释下。
看看你的代码死锁了没有,我看你的代码不是完全异步的代码,await与ConfigureAwait(false)可以避免死锁,把(true)改为false试试,阻塞时,所有异常都会用 AggregateException 包装后引发,不知道你的全局 try/catch 可以捕获到不,我的mvc都用ajax进行异步处理了,你这种服务器异步方式我用的也太少了,以前silverlight用过会
true改为false,肯定是没有问题的。我就是不明白,为什么我设置true之后,异步后面的代码不执行,并且也没有捕捉到异常。这个才是我疑惑的地方。
@SuperJoe: 你的代码没有完全异步,死锁了
@稳稳的河: 哪个地方,请给指出,谢谢。
@SuperJoe: 你这样当然死锁,你想用上下稳,这种写法完全错误,必须用ConfigureAwait(false),.net的AspNetSynchronizationContext,只能被一个线程独占
public class HomeController : Controller { public ActionResult Index() { TestTask();//线程A阻塞,等待TestTask返回 return View(); } private async Task TestTask() { try { WebRequest request = WebRequest.CreateHttp("http://localhost:4113/");//这个页面请求需要消耗5秒时间-----//你在内部开闭新线程 request.Method = "Get"; var response = await request.GetResponseAsync().ConfigureAwait(true); Debug.Write("异步外面执行"); } catch (Exception ex) { throw; } } }
@稳稳的河: var response = await request.GetResponseAsync().ConfigureAwait(false);是我知道的解决办法,服务端异步也去看的少,clr via c#里面讲了原理,有时间你去看下,我没有你需要获取上下文的解决办法
@稳稳的河: 在下面这种情况下,异步之后是可以夺回上下文继续执行的,
异步方法执行的很快,当异步方法执行完毕之后,之前的Http线程还没有执行完毕,可以简单理解成Index action还没有执行完毕,这个时候是可以夺回上下文继续执行异步后面的代码,也就是那句Debug代码。
所以不存在死锁。
@SuperJoe: 那他的是什么问题,他这是.netmvc的程序,窗口程序本来就不会存在死锁的问题,它有线程池来处理,Debug.Write("异步外面执行");是怎么夺回的?我不怎么明白,请教下
@SuperJoe: 你的TestTask()是在等待结果,这是一个线程,WebRequest.CreateHttp("http://localhost:4113/")也是一个线程,不被占用?当异步方法执行完毕之后,之前的Http线程还没有执行完毕?你的Http线程都是在异步方法里面,我不明白了
@稳稳的河: TestTask根本没有阻塞,调用这句代码的时候就返回了task, var response = await request.GetResponseAsync().ConfigureAwait(true); 如果我把Index里面代码改成这样: TestTask().GetAwaiter().GetResult();, 那才会形成死锁。
@SuperJoe:哦,调试的结果为准
@稳稳的河: 我测试过了。呵呵。
对异步 了解不多,也就猜测看下。
感觉像是主线程没有正确等待异步的回应而结束。而异步过程虽然正常执行,但没有成功返回到主线程中。
LZ 试试TestTask()增加返回值,从response中获取一个返回的响应值,来确认下是否能主线程能正常得到回馈。