c# - 需要一些关于 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
}
}
我的理解:
totalCountA++
是线程安全的,因为在那之前,代码是完全同步的。- 我知道
await
可能在线程池上运行,但我没想到恢复的代码await
将完全是多线程的。
根据一些答案/博客, async/await 不应创建新线程:
我真的在这里错过了一些大事。
解决方案
totalCountA++ 是线程安全的,因为在那之前,代码是完全同步的。
是的。这是因为async
方法开始在调用线程上执行,就像同步方法一样(归因:我)。
我知道 await 可能会在线程池上运行,但我没想到恢复 await 的代码会完全是多线程的。
await
不会在任何地方“运行” 。这就是您链接到的“没有线程”文章的重点。
现在,在 之后,await
其余代码需要在某个地方运行。await
默认情况下将捕获一个“上下文”并使用它来执行该async
方法的其余部分(属性:我)。那个“上下文”是SynchronizationContext.Current
,除非它是null
,在这种情况下它是TaskScheduler.Current
。在控制台应用程序中,这意味着上下文是线程池上下文,因此任何可用的线程池线程都将执行该async
方法的其余部分。
推荐阅读
- python - 如何将栅格格式的标签数据加载到 Keras/Tensorflow 中
- c++ - 如何在 C 中编译,但如果我使用任何 C++ 会抛出错误?
- c# - 在 C# 中检测 Python 缩进开始
- c++ - 使用 Qt API 获取连接到我的计算机的设备列表
- javascript - 在 React 组件中访问嵌套的 JSON 数据
- javascript - 按钮数组的onClick函数不起作用
- bazaar - 有没有人为 Windows 构建过 BZR 2.7.0?
- firebase - 如何在不登录的情况下通过 Firebase Auth 创建新用户?
- android - 防止安装特定制造商-API 组合
- r - 如何迭代地形成文本行以显示在 R 闪亮的应用程序中?