为什么我的异步ASP.NET Web API控制器阻塞主线程?
我有一个ASP.NET Web API控制器,我原本认为它可以异步操作。 控制器设计为第一次请求hibernate20秒,但立即为任何后续请求提供服务。 所以我预期的时间表是这样的:
- 提出要求1。
- 提出要求2。
- 提出要求3。
- 请求2返回。
- 请求3返回。
- 等~20秒。
- 请求1返回。
相反,在请求1完成之前, 没有请求返回。
我可以确认(基于调试输出),入口线程和困线程id是不同的。 我故意使用TaskCreationOptions.LongRunning
强制将睡眠强制到一个单独的线程,但是在睡眠完成之前,应用程序仍然拒绝为任何新请求提供服务。
我是否遗漏了有关异步Web API控制器如何工作的基本信息?
public class ValuesController : ApiController { private static bool _firstTime = true; public async Task Get() { Debug.WriteLine("Entry thread id: {0}. Sync: {1}", Thread.CurrentThread.ManagedThreadId, SynchronizationContext.Current); await LongWaitAsync(); return "FOOBAR"; } private Task LongWaitAsync() { return Task.Factory.StartNew(() => { if (_firstTime) { _firstTime = false; Debug.WriteLine("Sleepy thread id: {0}. Sync: {1}", Thread.CurrentThread.ManagedThreadId, SynchronizationContext.Current); Thread.Sleep(20000); Debug.WriteLine("Finished sleeping"); } }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); } }
这实际上与服务器无关,而且与客户端有关。 Chrome和Firefox似乎都不希望发送他们认为是“重复”请求的内容,直到第一个请求得到响应。 任一浏览器的单独“私有”会话将立即从第二个请求返回。 Internet Explorer 9似乎没有出现此行为。
为了与客户端实现隔离,我将以下客户端放在一起。
class Program { static void Main(string[] args) { var t1 = Task.Run(() => FetchData(1)); var t2 = Task.Run(() => FetchData(2)); var t3 = Task.Run(() => FetchData(3)); var index = Task.WaitAny(t1, t2, t3); Console.WriteLine("Task {0} finished first", index + 1); Task.WaitAll(t1, t2, t3); Console.WriteLine("All tasks have finished"); Console.WriteLine("Press any key"); Console.ReadKey(true); } static void FetchData(int clientNumber) { var client = new WebClient(); string data = client.DownloadString("http://localhost:61852/api/values"); Console.WriteLine("Client {0} got data: {1}", clientNumber, data); } }
它的输出是:
- 客户端2获取数据:“FOOBAR”(在启动后的毫秒内)
- 客户3获得数据:“FOOBAR”
- 任务2先完成
- (在这里等很久)
- 客户1得到数据:“FOOBAR”
- 所有任务都已完成
在我的情况下这里输出(它切换到另一个从5到10的线程):
Entry thread id: 5. Sync: System.Web.LegacyAspNetSynchronizationContext Sleepy thread id: 10. Sync: Finished sleeping The thread '' (0x2c84) has exited with code 0 (0x0). Entry thread id: 7. Sync: System.Web.LegacyAspNetSynchronizationContext The thread ' ' (0x1818) has exited with code 0 (0x0). Entry thread id: 5. Sync: System.Web.LegacyAspNetSynchronizationContext The thread ' ' (0xd4c) has exited with code 0 (0x0). The thread ' ' (0x2c30) has exited with code 0 (0x0).
这可能是由于环境和机器运行(单核)使运行时决定如何运行它。
- 如何在客户端获取DotNetOpenAuth.OAuth2返回的错误消息?
- Web.API中的自定义授权
- WebAPI POST 没有绑定
- 将json发布到mvc 4 WebApi控制器操作。 为什么不反序列化我的数组呢?
- 为什么要处理ASP.NET Web Api的依赖性解析器?
- 无法将当前JSON数组(例如)反序列化为类型’TenantManagementWebApi.Entities.Tenant
- webapi2中DataMember和JsonProperty之间的区别
- 从MVC的DependencyResolver过渡到AutofacWebApiDependencyResolver – 哪里是.Current?
- 如何在HttpClient response.ReasonPhrase中获取真正的错误消息?