如何确保Task不会重用TPL中的调用线程?

时间:2019-06-24 09:40:50

标签: asp.net multithreading asynchronous asp.net-web-api task-parallel-library

我正在开发ASP.Net Web Api。我在需要时使用async方法来运行一些异步代码。当需要阻塞这些async方法以获取结果时,我还有一些特定的情况。由于在ASP.Net Request线程中阻止异步方法会导致死锁(解释为什么可以找到here),所以我决定使用Task.Run在单独的任务中阻止异步方法。考虑以下示例:

public class TestController : ApiController
{
    // This method must be synchronous
    public void Test()
    {
        Debug.WriteLine($"Main Thread {Thread.CurrentThread.ManagedThreadId}");
        // I must use a Task here because otherwise I will have to block async code which will cause a deadlock
        var task = Task.Run(() =>
        {
            Debug.WriteLine($"Child Thread {Thread.CurrentThread.ManagedThreadId}");
            SomeAsynchronousWork().GetAwaiter().GetResult();
        });
        task.GetAwaiter().GetResult();
    }

    public async Task SomeAsynchronousWork()
    {
       // some work that must be done asynchronously
    }
}

现在有时运行Test方法时,我可以看到这种调试输出

Main Thread 5
Child Thread 5

这意味着该任务在导致死锁的同一线程上运行。这对我来说很奇怪,因为据我所知Task.Run应该在ThreadPool线程上运行任务,并且它永远不能成为主线程(在本示例中为ASP.Net Request线程)。显然并非如此。我有问题:

  1. 这怎么可能?
  2. 如何确保任务将始终在ThreadPool线程上运行而不在调用的ASP.Net Request线程上运行?

还要注意,由于某些细节我不想在这里解释,因此我必须阻止异步方法,并且没有办法使我的方法一直到顶部都是异步的。

0 个答案:

没有答案