C#中向多异步函数传递对象(各更新独立字段)是否存在并发问题?
问题:C#异步并发更新对象不同独立字段是否需要考虑并发问题?
我需要将一个Error对象传给多个异步函数,每个函数仅更新该对象的不同独立字段,疑惑这样的操作是否会引发与List相关的并发问题?
代码示例:
class Error { public object fieldA; public object fieldB; public object fieldC; } var error = new Error(); var awaitedTasks = new List<Task>(); awaitedTasks.Add(funcA(error)); // 仅更新fieldA的异步函数 awaitedTasks.Add(funcB(error)); // 仅更新fieldB的异步函数 awaitedTasks.Add(funcC(error)); // 仅更新fieldC的异步函数 await Task.WhenAll(awaitedTasks); private async Task funcA(Error error) { error.fieldA = await FetchAFromDbAsync(); } private async Task funcB(Error error) { error.fieldB = await FetchBFromDbAsync(); } private async Task funcC(Error error) { error.fieldC = await FetchCFromDbAsync(); }
补充说明:此处我们通过不同函数为Error对象的不同字段补充信息。
回答
你的这种场景不会引发并发问题,也不会出现类似List的并发异常,原因如下:
- 每个异步函数仅操作
Error对象的独立字段,字段之间不存在共享状态的读写冲突,彼此的修改互不干扰 - 引用类型字段的赋值操作(
error.fieldA = ...)在C#中是原子操作,本质是写入一个内存地址,这个过程不会被中断,不会出现半完成的赋值状态 - 代码中对
List<Task>的操作(添加任务)都是在同一个线程中完成的,之后才通过Task.WhenAll等待所有任务完成,不存在多线程并发修改集合的情况
注意事项
如果后续业务逻辑发生变化,出现以下场景时必须考虑并发安全:
- 多个异步函数需要修改同一个字段
- 某个字段的更新涉及「先读取字段值,再基于旧值计算新值,最后赋值」的复合操作(比如
error.fieldA = (int)error.fieldA + 1) - 字段为复杂结构体且需要修改结构体内部的多个子字段(此时结构体赋值不是原子操作)
内容的提问来源于stack exchange,提问作者Anuj
相关产品推荐
相关产品推荐

