首页 > 解决方案 > 需要一些关于 async/await 和线程安全的解释

问题描述

还有一个关于线程安全和异步/等待的问题。我不明白为什么我的第二个增量不是线程安全的。

class Program
{
    static int totalCountB = 0; 
    static int totalCountA = 0;
    
    static async Task AnotherTask()
    {
        totalCountA++; // Thread safe
        await Task.Delay(1);
        totalCountB++; // not thread safe 
    }

    static async Task SpawnManyTasks(int taskCount)
    {
        await Task.WhenAll(Enumerable.Range(0, taskCount)
            .Select(_ => AnotherTask()));
    }

    static async Task Main()
    {
        await SpawnManyTasks(10_000);

        Console.WriteLine($"{nameof(totalCountA)} : " + totalCountA); // Output 10000
        Console.WriteLine($"{nameof(totalCountB)} : " + totalCountB); // Output 9856
    }
}

我的理解:

根据一些答案/博客, async/await 不应创建新线程:

我真的在这里错过了一些大事。

标签: c#async-await

解决方案


totalCountA++ 是线程安全的,因为在那之前,代码是完全同步的。

是的。这是因为async方法开始在调用线程上执行,就像同步方法一样(归因:我)。

我知道 await 可能会在线程池上运行,但我没想到恢复 await 的代码会完全是多线程的。

await不会在任何地方“运行” 。这就是您链接到的“没有线程”文章的重点。

现在,在 之后await其余代码需要在某个地方运行。await默认情况下将捕获一个“上下文”并使用它来执行该async方法的其余部分(属性:我)。那个“上下文”是SynchronizationContext.Current,除非它是null,在这种情况下它是TaskScheduler.Current。在控制台应用程序中,这意味着上下文是线程池上下文,因此任何可用的线程池线程都将执行该async方法的其余部分。


推荐阅读