【问题标题】:What gets put on a thread pool thread in Task when using async/await?使用 async/await 时,Task 中的线程池线程上会放什么?
【发布时间】:2012-11-01 10:21:19
【问题描述】:

请考虑以下代码

    public static async Task<int> Answer()
    {
        await Task.Delay(1000);
        return 42;
    }

    static void Main(string[] args)
    {
        for (int j = 0; j < 20; j++)
        {
            Console.WriteLine(j +" " + Thread.CurrentThread.IsThreadPoolThread);
            if (j == 1)
            {
                new Task( async ()=>
                    {
                        int answer = await Answer();
                        Console.WriteLine(answer + " " + Thread.CurrentThread.IsThreadPoolThread);
                    }).Start();
            }

            Thread.Sleep(200);
        }

        return;

你能猜出打印答案时的CurrentThread.IsThreadPoolThread是什么吗?

看来Task.Delay(..) 正在这样做,因为如果我删除等待,那么答案就是False。但是,我似乎找不到 Delay 实际上在文档中将东西放在线程池中。

这让我想到了更一般的问题。除了Run(..)之外,Task实际上启动了一个线程池线程吗?

编辑:
new Task(...) 替换为Ask()

    public static async void Ask()
    {
        int answer = await Answer();
        Console.WriteLine(answer + " " + Thread.CurrentThread.IsThreadPoolThread);
    }

产生相同的结果

【问题讨论】:

    标签: c# multithreading threadpool


    【解决方案1】:

    正如我在async / await intro 帖子中所描述的,默认情况下await 将捕获当前“上下文”并使用它来执行延续(await 之后的代码)。这个“上下文”是SynchronizationContext.Current,除非它是null,在这种情况下它是TaskScheduler.Current

    我还在我的博客上描述了using async on Console apps。控制台应用程序不提供SynchronizationContext,因此“上下文”回退到TaskScheduler.Current。由于当前正在执行的Task是在线程池上运行的,所以TaskScheduler.CurrentTaskScheduler.Default一样,都是线程池任务调度器。

    这就是您的代码在线程池线程上恢复的原因。这是正确的行为。

    【讨论】:

    • 所以没有有上下文,会总是让回调在TP线程上运行吗?这是否还包括Task.ConfigureAwait(false),即设置为 false 将始终在 TP 线程上执行回调?
    • 实际上,我不确定我是否完全理解“由于当前正在执行的任务正在线程池上运行”。为什么Task在线程池上运行?
    • 当你说new Task ... Start 而不提供TaskScheduler 时,它将在线程池上运行;这与Task.Run 非常相似。是的,如果您使用ConfigureAwait(false) await 一个操作(尚未完成),那么它将始终在线程池上执行延续。
    • 我已经编辑了替换 new Task.Start(..) 的帖子。结果是一样的。我认为这是因为对 Task.Start(..) 的调用现在是隐式的。结论是通常所有任务都可以在没有明确请求的情况下在线程池上运行吗?你认为可以拨打Answer(..)阻塞吗?
    • 使用新代码,Answer 开始在控制台应用程序主线程上执行,该线程仍然没有SynchronizationContextTaskScheduler,因此它仍将使用TaskScheduler.Default。这就是为什么您会看到相同的结果,这仍然是正确的。没有对Task.Start 的隐式调用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-06
    • 1970-01-01
    • 1970-01-01
    • 2021-11-24
    相关资源
    最近更新 更多