线程池线程上没有调度任务延续

时间:2021-01-21 21:01:53

I was reading about SynchronizationContext and its use with the async/await methods (link). From my understanding, in a Console application where the SynchronizationContext is null, the continuation of an awaited method (Task) will be scheduled with the default scheduler which would be the ThreadPool.

我正在阅读关于SynchronizationContext及其与async/ waiting方法(link)的使用。根据我的理解,在同步上下文为null的控制台应用程序中,等待的方法(任务)的延续将与缺省调度器(将是ThreadPool)一起调度。

But if I run this console app, you'll see from the output that the the continuation is run on the worker thread that I created:

但是如果我运行这个控制台应用程序,你会从输出中看到,延续在我创建的工作线程上运行:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("MainThreadId=" + Thread.CurrentThread.ManagedThreadId);
        Method1().ContinueWith(t =>
        {
            Console.WriteLine("After Method1. ThreadId=" + Thread.CurrentThread.ManagedThreadId);
        });

        Console.ReadKey();
    }

    public static async Task Method1()
    {
        Console.WriteLine("Method1 => Entered. ThreadId=" + Thread.CurrentThread.ManagedThreadId);

        TaskCompletionSource<bool> completionSource = new TaskCompletionSource<bool>();
        Thread thread = new Thread(() =>
        {
            Console.WriteLine("Method1 => Started new thread. ThreadId=" + Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(2000);
            completionSource.SetResult(true);
        });

        thread.Start();

        await completionSource.Task;

        Console.WriteLine("Method1 => After WorkerThread. ThreadId=" + Thread.CurrentThread.ManagedThreadId);
    }
}

And here is the output:

这是输出:

MainThreadId=10
Method1 => Entered. ThreadId=10
Method1 => Started new thread. ThreadId=11
Method1 => After WorkerThread. ThreadId=11
After Method1. ThreadId=12

As you can see, "After WorkerThread" was outputted on the same thread as my workerthread, but not on the threadpool.

如您所见,“After WorkerThread”在与我的WorkerThread相同的线程上输出,但不在threadpool上。

I found a similar question but the guy was using Mono and they were saying that this was a bug. On my side, I built this code with in Visual Studio and ran it under Windows 7 and .Net 4.5.2 installed on my machine.

我发现了一个类似的问题,但是那个人用的是Mono,他们说这是一个bug。在我这边,我在Visual Studio中构建了这段代码,并在安装在我的机器上的Windows 7和。net 4.5.2下运行它。

Could someone please explain this behaviour?

谁能解释一下这种行为吗?

1 个解决方案

#1


5  

It's because of an implementation detail that I documented on my blog: the continuation created by await is scheduled using the ExecuteSynchronously flag. In that case, when it is time to fire the continuation (i.e., in the TaskCompletionSource<T>.SetResult call on the worker thread), the default scheduler first attempts to determine whether it can run on the current thread.

这是因为我在博客中记录了一个实现细节:wait创建的continuation使用executesynchronityflag进行调度。在这种情况下,是时候启动continuation了(例如。在TaskCompletionSource < T >。在工作线程上调用SetResult),默认的调度器首先尝试确定它是否可以在当前线程上运行。

Since the worker thread has no TaskScheduler that will reject executing the task synchronously, the ExecuteSynchronously flag will cause the thread pool task scheduler to just execute the task synchronously (i.e., on the calling thread).

由于工作线程没有能够拒绝同步执行任务的任务调度程序,所以executesynchronity标志将导致线程池任务调度程序仅同步执行任务(即,在调用线程上)。

#1


5  

It's because of an implementation detail that I documented on my blog: the continuation created by await is scheduled using the ExecuteSynchronously flag. In that case, when it is time to fire the continuation (i.e., in the TaskCompletionSource<T>.SetResult call on the worker thread), the default scheduler first attempts to determine whether it can run on the current thread.

这是因为我在博客中记录了一个实现细节:wait创建的continuation使用executesynchronityflag进行调度。在这种情况下,是时候启动continuation了(例如。在TaskCompletionSource < T >。在工作线程上调用SetResult),默认的调度器首先尝试确定它是否可以在当前线程上运行。

Since the worker thread has no TaskScheduler that will reject executing the task synchronously, the ExecuteSynchronously flag will cause the thread pool task scheduler to just execute the task synchronously (i.e., on the calling thread).

由于工作线程没有能够拒绝同步执行任务的任务调度程序,所以executesynchronity标志将导致线程池任务调度程序仅同步执行任务(即,在调用线程上)。