【问题标题】:Does ConfigureAwait affect non-threadpool threads only?ConfigureAwait 是否仅影响非线程池线程?
【发布时间】:2016-06-12 20:10:08
【问题描述】:

我正在玩 ConfigureAwait 一点,因为我想了解它是如何工作的。

因此,我编写了以下小型控制台应用程序(实际运行在 LINQPad 中):

void Main()
{
    // Use dispatcher to execute the code on STA thread
    Dispatcher.CurrentDispatcher.Invoke(() => Run());
}

private async static Task Run()
{
    var continueOnCapturedContext1 = true;
    var continueOnCapturedContext2 = true;

    PrintThreadID();
    await Task.Run(() => PrintThreadID()).ConfigureAwait(continueOnCapturedContext1);
    PrintThreadID();
    await Task.Run(() => PrintThreadID()).ConfigureAwait(continueOnCapturedContext2);   
    PrintThreadID();
}

private static void PrintThreadID()
{
    Console.Write(Thread.CurrentThread.ManagedThreadId.ToString("00") + "\t");
}

我得到以下输出:

A) 真/真

var continueOnCapturedContext1 = true;
var continueOnCapturedContext2 = true;

1) 11 19 11 07 11

2) 11 09 11 12 11

3) 11 06 11 06 11

预期:调度程序线程 (11) 被捕获,等待的任务在不同或相同的线程池线程上执行。

B) 假/假

var continueOnCapturedContext1 = false;
var continueOnCapturedContext2 = false;

1) 11 23 23 22 22

2) 11 19 19 19 19

3) 11 10 10 10 10

同样预期:未捕获 SynchronizationContext,因此后续可等待和不可等待代码在线程池线程上运行(通常相同)。

C) 假/真

var continueOnCapturedContext1 = false;
var continueOnCapturedContext2 = true;

1) 11 14 14 06 06

2) 11 20 20 20 20

3) 11 17 17 08 08

输出 1 和 3 的结果很奇怪。 2. awaitbale 任务是使用“在捕获的上下文中继续”选项执行的,所以我希望它与调用它的代码在同一线程上运行。

看来,如果之前已经调用过,ConfigureAwait(true/false) 对后续的等待调用没有影响,对吧?

【问题讨论】:

  • 请注意,synccontext 可以为所欲为。它可以在任何线程上运行您的代码,甚至取决于硬币的翻转。因此,了解常用 上下文的作用非常重要。 ConfigureAwait(false) 只是说“即使存在也不要使用上下文”。

标签: c# async-await task-parallel-library


【解决方案1】:

2. awaitbale 任务是使用“在捕获的上下文中继续”选项执行的,所以我希望它与调用它的代码在同一个线程上运行。

假设“上下文 == 线程”,但事实并非如此。使用线程池的同步上下文将在线程池中的 any 线程上恢复。现在,如果您捕获同步上下文,您仍然会处于“线程池中的线程”。

所以是的,如果您已经在线程池线程上,那么无论您是否捕获同步上下文都无关紧要......继续仍然会在线程池线程上结束。但值得指出的是,具有多个线程的不同同步上下文是完全合理的,并且捕获同步上下文将返回到这些线程中的一个,但不一定是同一个。

如果之前已经调用过ConfigureAwait(true/false),那么它似乎对后续的等待调用没有影响,对吧?

不完全是。如果任务需要使用延续,就会出现这种情况。如果您调用 ConfigureAwait 的第一个任务已经完成,代码将继续同步执行 - 所以此时,第二个 ConfigureAwait 很重要。

例子:

using System;
using System.Windows.Forms;
using System.Threading;
using System.Threading.Tasks;

class Test
{    
    static void Main()
    {
        var form = new Form();
        form.Load += async (sender, args) =>
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
            await Task.FromResult(10).ConfigureAwait(false);
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
            await Task.Delay(1000).ConfigureAwait(false);
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        };
        Application.Run(form);
    }
}

示例输出:

1
1
5

所以第二个Console.WriteLine 表明尽管ConfigureAwait(false) 代码仍在同一个线程上运行,因为Task.FromResult 返回一个已经完成的任务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-05
    • 2011-09-10
    • 1970-01-01
    • 2016-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多