C# 为什么我的异步ASP.NET Web API控制器会阻止主线程?
我有一个ASP.NET Web API控制器,我本以为它会异步运行。控制器设计为在第一次请求时休眠20秒,但立即为任何后续请求提供服务。因此,我预期的时间线如下:C# 为什么我的异步ASP.NET Web API控制器会阻止主线程?,c#,asp.net-web-api,async-await,C#,Asp.net Web Api,Async Await,我有一个ASP.NET Web API控制器,我本以为它会异步运行。控制器设计为在第一次请求时休眠20秒,但立即为任何后续请求提供服务。因此,我预期的时间线如下: 提出请求1 提出请求2 提出请求3 请求2返回 请求3个返回 等待约20秒 请求1返回 相反,no请求返回,直到请求1完成 我可以确认(基于调试输出),入口线程和休眠线程id是不同的。我故意使用TaskCreationOptions.LongRunning将睡眠强制到一个单独的线程上,但在睡眠完成之前,应用程序仍然拒绝服务任何新请求
TaskCreationOptions.LongRunning
将睡眠强制到一个单独的线程上,但在睡眠完成之前,应用程序仍然拒绝服务任何新请求
我是否遗漏了异步Web API控制器如何真正工作的一些基本信息
公共类值控制器:ApiController
{
私有静态bool_firstTime=true;
公共异步任务Get()
{
WriteLine(“入口线程id:{0}.Sync:{1}”,
Thread.CurrentThread.ManagedThreadId,
SynchronizationContext.Current);
等待LongWaitAsync();
返回“FOOBAR”;
}
私有任务LongWaitAsync()
{
返回Task.Factory.StartNew(()=>
{
如果(第一次)
{
_第一次=错误;
WriteLine(“休眠线程id:{0}.Sync:{1}”,
Thread.CurrentThread.ManagedThreadId,
SynchronizationContext.Current);
睡眠(20000);
Debug.WriteLine(“已完成睡眠”);
}
},
取消令牌。无,
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);
}
}
它的输出是:
入口线程id:5。Sync:System.Web.legacyapsnetsynchronizationcontext
休眠线程id:10。同步:
睡完了
线程“”(0x2c84)已退出,代码为0(0x0)。
入口线程id:7。Sync:System.Web.legacyapsnetsynchronizationcontext
线程“”(0x1818)已退出,代码为0(0x0)。
入口线程id:5。Sync:System.Web.legacyapsnetsynchronizationcontext
线程“”(0xd4c)已退出,代码为0(0x0)。
线程“”(0x2c30)已退出,代码为0(0x0)。
这可能是由于环境和机器运行(单核)使得运行时决定如何运行它。作为第一步,我将
\u firstTime
标记为volatile
,确保不同的线程可以看到它不断变化。您使用哪个web服务器作为主机?将\u firstTime
标记为volatile
没有区别。我尝试过在Win 7 Pro上使用IIS Express 8.0和IIS 7.5托管。@Snixtor-这可能没有什么区别,但无论如何都应该这样做。@Damien_不信者适时指出。我承认我必须查找它的含义,它肯定与我的示例代码有关。我想我疯了。谢谢你的启示!
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);
}
}
Entry thread id: 5. Sync: System.Web.LegacyAspNetSynchronizationContext
Sleepy thread id: 10. Sync:
Finished sleeping
The thread '<No Name>' (0x2c84) has exited with code 0 (0x0).
Entry thread id: 7. Sync: System.Web.LegacyAspNetSynchronizationContext
The thread '<No Name>' (0x1818) has exited with code 0 (0x0).
Entry thread id: 5. Sync: System.Web.LegacyAspNetSynchronizationContext
The thread '<No Name>' (0xd4c) has exited with code 0 (0x0).
The thread '<No Name>' (0x2c30) has exited with code 0 (0x0).