最近的 PR 评论中出现了一个关于是否AsyncLocal<IDictionary<>>应该使用ConcurrentDictionary<>. 我的想法是不需要这样做,因为 AsyncLocal 值不会同时被多个线程访问。但我想确定一下。
我们是否需要担心 AsyncLocal 中保存的对象的线程安全性?请解释为什么或为什么不。证明所断言答案的单元测试的奖励积分。
AsyncLocal可用于异步控制流中的所有线程。
让我们看这个例子:
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp15
{
class Program
{
static AsyncLocal<string> _asyncLocalString = new AsyncLocal<string>();
static async Task Main(string[] args)
{
_asyncLocalString.Value = "TestString";
var tasks = Enumerable.Range(0, 10).Select(_ => GetString());
var results = await Task.WhenAll(tasks);
}
private static async Task<string> GetString()
{
await Task.Yield();
return _asyncLocalString.Value + Thread.CurrentThread.ManagedThreadId;
}
}
}
Run Code Online (Sandbox Code Playgroud)
这里多个线程可以同时访问值“TestString”。
此外,一旦从异步本地中提取该值,就需要像任何其他引用一样对待它。如果它在回调中使用、返回给调用者、在闭包中捕获等,则它可以暴露给其他线程。对于引用类型,可以在外部修改值,并且可能会发生竞争条件。
更新: 这是一个带有字典的示例:
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp15
{
class Program
{
static AsyncLocal<Dictionary<string, int>> _asyncLocalDict = new AsyncLocal<Dictionary<string, int>>();
static async Task Main(string[] args)
{
_asyncLocalDict.Value = new Dictionary<string, int>();
var tasks = Enumerable.Range(0, 10).Select(_ => Race());
await Task.WhenAll(tasks);
}
private static async Task Race()
{
await Task.Yield();
var dict = _asyncLocalDict.Value;
if (!dict.ContainsKey("race")) dict["race"] = 0;
dict["race"]++;
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1977 次 |
| 最近记录: |