简体   繁体   中英

How to determine which thread a method will executes on when using TPL?

I know that the TPL is task-oriented, while the classic threading model is worker-oriented. Tasks let you focus primarily on what problem you want to solve instead of on the mechanics of how it will get done . But I am still a bit confused when it comes to thread and task relationship.

Below is a demo code:

namespace AsyncUnderTheHood
{
    class Program
    {

        static void Main(string[] args)
        {
            Console.WriteLine("Main Start : {0}", Thread.CurrentThread.ManagedThreadId);
            AwaitTest();
            Console.WriteLine("Main End : {0}", Thread.CurrentThread.ManagedThreadId);
            Console.ReadLine();
        }

        public static void DoWork()
        {
            Console.WriteLine("DoWork Start: {0}", Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(5000);
            Console.WriteLine("DoWork End: {0}", Thread.CurrentThread.ManagedThreadId);
        }

        public async static void AwaitTest()
        {
            Console.WriteLine("AwaitTest Start : {0}", Thread.CurrentThread.ManagedThreadId);
            Task t = new Task(DoWork);
            t.Start();
            await t;
            Console.WriteLine("AwaitTest Done : {0}", Thread.CurrentThread.ManagedThreadId);
        }
    }
}

The output is like this:

Main Start : 1
AwaitTest Start : 1   <------------ A
DoWork Start: 3
Main End : 1
DoWork End: 3
AwaitTest Done : 3    <------------ B

My question is, why A and B is on different thread?

The same method is executed on different threads, will this cause issue when thread affinity is important?

why A and B is on different thread?

First, if your Task s are scheduled by the default scheduler, then there is no guarantee which Thread will a Task run on. And the parts of AwaitTest() are executed separately, so there is no guarantee they will run on the same thread.

Second, the default scheduler uses the ThreadPool to execute Task s. And the first part of each async method runs synchronously. In your case, this means the first part of AwaitTest() will run on the main thread and the second part will run on some ThreadPool thread. So, you're actually guaranteed that they won't run on the same thread.

will this cause issue when thread affinity is important?

It certainly could. But it will work correctly in the most common case where thread affinity is important: GUI programming. This is because GUI applications have SynchronizationContext set, which means that if the first part of an async method runs on the UI thread, the second part will run there too (unless you disable this by using ConfigureAwait(false) ).

But in other cases, it will cause problems. For example, take the following code:

Monitor.Enter(lockObject);
await someTask;
Monitor.Exit(lockObject);

This code wouldn't work in a console application ( Exit() will most likely throw SynchronizationLockException ), because the Exit() can run on different thread than Enter() .

You've asked the system to "await" a task. What you're really asking is that the thread that invoked await should continue running and everything after the await is a "continuation" that will get run asynchronously when the task is done. Since there's no "message pump" in a console application, there's no easy way to marshal back to the "main" thread and thus the continuation just continues on with the asynchronous Task 's thread. If you performed the same test in a WinForm or WPF application, the continuation would run on the UI thread.

这篇博客文章很好地描述了TPL如何使用多个任务队列,将工作窃取到现有线程池之上,以获得最佳性能。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM