为什么我的异步的ASP.NET Web API控制器阻塞主线程? [英] Why is my async ASP.NET Web API controller blocking the main thread?

查看:468
本文介绍了为什么我的异步的ASP.NET Web API控制器阻塞主线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我,我将有一个ASP.NET Web API控制器的思想的将异步操作。控制器被设计为睡20秒在第一次请求,而是立即服务任何后续请求。所以,我的预期时间表会是这样的:


  1. 培养要求1。

  2. 培养要求2。

  3. 培养要求3。

  4. 请求2回报。

  5. 请求3的回报。

  6. 等待〜20秒。

  7. 请求1的回报。

相反,请求返回,直到请求1结束。

我可以证实(基于调试输出),该条目线程困线程ID是不同的。我有意使用 TaskCreationOptions.LongRunning 来睡眠强制到一个单独的线程,但仍拒绝申请,直到睡眠已经完成,以服务于任何新的请求。

我失去了一些关于异步网页API控制器到底是如何工作的根本?


 公共类Values​​Controller:ApiController
{
    私人静态布尔_firstTime = TRUE;    公共异步任务<串GT;得到()
    {
        的Debug.WriteLine(进入线程ID:{0}同步:{1},
            Thread.CurrentThread.ManagedThreadId,
            SynchronizationContext.Current);
        等待LongWaitAsync();
        返回FOOBAR
    }    私人任务LongWaitAsync()
    {
        返回Task.Factory.StartNew(()=>
            {
                如果(_firstTime)
                {
                    _firstTime = FALSE;
                    的Debug.WriteLine(断头线程ID:{0}同步:{1},
                        Thread.CurrentThread.ManagedThreadId,
                        SynchronizationContext.Current);
                    Thread.sleep代码(20000);
                    的Debug.WriteLine(说完睡觉);
                }
            },
            CancellationToken.None,
            TaskCreationOptions.LongRunning,
            TaskScheduler.Default);
    }
}


解决方案

这实际上无关与服务器,什么都做的客户端。无论Chrome和Firefox似乎没有要送什么,他们认为一个重复请求,直到第一个拥有它的响应。无论是浏览器的一个单独的私人会议将于第二个请求立即返回。 Internet Explorer 9中似乎并没有表现出这种行为。

要从客户端实现隔离,我总结了以下客户端。

 类节目
{
    静态无效的主要(字串[] args)
    {
        变种T1 = Task.Run(()=> FetchData(1));
        变种T2 = Task.Run(()=> FetchData(2));
        变种T3 = Task.Run(()=> FetchData(3));        变种指数= Task.WaitAny(T1,T2,T3);
        Console.WriteLine(任务{0}完成了第一个指数+ 1);        Task.WaitAll(T1,T2,T3);
        Console.WriteLine(所有任务已完成);        Console.WriteLine(preSS任意键);
        Console.ReadKey(真);
    }    静态无效FetchData(INT clientNumber)
    {
        VAR的客户=新的WebClient();
        字符串数据= client.DownloadString(HTTP://本地主机:61852 / API /值);
        Console.WriteLine(客户{0}得到数据:{1},clientNumber,数据);
    }
}

它的输出为:


  1. 2的客户端得到数据:(内启动的毫秒)FOOBAR

  2. 客户端3得到的数据:FOOBAR

  3. 任务2完成了第一个

  4. (漫长的等待在这里)

  5. 客户端1获得的数据:FOOBAR

  6. 所有任务已完成

I have an ASP.NET Web API controller that I would have thought would operate asynchronously. The controller is designed to sleep 20 seconds for the first request, but service any subsequent requests immediately. So my anticipated timeline would be something like:

  1. Raise request 1.
  2. Raise request 2.
  3. Raise request 3.
  4. Request 2 returns.
  5. Request 3 returns.
  6. Wait ~20 seconds.
  7. Request 1 returns.

Instead, no requests return until request 1 is finished.

I can confirm (based on the debug outputs), that the entry thread and sleepy thread id are different. I've intentionally used TaskCreationOptions.LongRunning to force the sleep onto a separate thread, but still the application refuses to service any new requests until that sleep has finished.

Am I missing something fundamental about how async Web API controllers really work?


public class ValuesController : ApiController
{
    private static bool _firstTime = true;

    public async Task<string> 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);
    }
}

解决方案

This actually has nothing to do with the server, and everything to do with the client. Both Chrome and Firefox don't appear to want to send what they deem a "duplicate" request until the first one has its response. A separate "private" session of either browser will return from the second request immediately. Internet Explorer 9 doesn't seem to exhibit this behaviour.

To isolate from client implementations, I put together the following client.

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);
    }
}

It's output goes:

  1. Client 2 got data: "FOOBAR" (within milliseconds of startup)
  2. Client 3 got data: "FOOBAR"
  3. Task 2 finished first
  4. (long wait here)
  5. Client 1 got data: "FOOBAR"
  6. All tasks have finished

这篇关于为什么我的异步的ASP.NET Web API控制器阻塞主线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆