我什么时候需要担心导致多线程的任务?

When do I need to worry about tasks leading to multithreading?

假设我有这样的代码:

...
var task1 = DoWorkAsync(1);
var task2 = DoWorkAsync(2);
await Task.WhenAll(task1, task2);
...

private async Task DoWorkAsync(int n)
{
    // Async HTTP request that we ConfigureAwait(to be determined).

    // Some CPU-bound work that isn't thread-safe.
}

因此,如果我在 WPF 应用程序中并且我没有 ConfigureAwait(false) HTTP 请求,我在这里安全吗?这两个 HTTP 请求可以并发进行,但是任务必须在 UI 线程上恢复,所以 CPU 绑定的工作不是多线程的吗?但是,如果我这样做 ConfigureAwait(false),任务可以在不同的线程池线程上并行恢复其 CPU 绑定的工作,所以我有麻烦了?

如果我在 ASP.NET 中,这两种情况都可能发生,因为同步上下文与 WPF 之类的线程没有任何关系?

如果我在控制台应用程序中怎么办?

如何谈论 DoWorkAsync?我是说“同时 DoWorkAsync 不安全”吗?

有重新设计的正常方法吗?并发执行的重要部分是 HTTP 请求,而不是 CPU 绑定的工作,所以我是否使用锁或其他东西(以前从未使用过)?

So if I'm in a WPF app and I don't ConfigureAwait(false) on the HTTP request, am I safe here?

如果这是在 UI 线程上调用的,那么是的,你是对的。 UI 上下文一次只允许一个线程(具体来说是 UI 线程),因此 CPU 绑定的部分将 运行 在 UI线程和互不干扰。这是一个很常见的技巧。

if I do ConfigureAwait(false), the tasks can resume their CPU-bound work in parallel on different thread pool threads so I'm in trouble?

是的。因为ConfigureAwait(false)表示"the CPU-bound work doesn't need the context",所以可以运行在线程池上并行

If I'm in ASP.NET

Classic ASP.NET 具有一次一个线程的请求上下文,因此它的行为相同;如果没有 ConfigureAwait(false).

是安全的

ASP.NET 核心 没有 有一个请求上下文(嗯,不是 SynchronizationContext,无论如何),所以它可以是 运行在该平台上并行。我称之为 "implicit parallelism" in my blog post on the ASP.NET Core SynchronziationContext.

And what if I'm in a console app?

没有上下文,可以运行并行

How do I talk about DoWorkAsync?

"This method requires a non-free-threaded SynchronizationContext."

do I use a lock or something

这是最好的方法,是的:

private readonly object _mutex = new object();
private async Task DoWorkAsync(int n)
{
  await HttpRequestAsync().ConfigureAwait(false);
  lock (_mutex)
  {
    // Some CPU-bound work that isn't thread-safe.
  }
}