PLinq 和源 IEnumerable 的线程安全





0/5 (0投票)
PLinq 和源 IEnumerable 的线程安全
当我发现 PLINQ 从多个线程调用源 IEnumerable
时,我开始思考:这怎么可能工作?例如,当有人编写如下代码时
Enumerable.Range(1,1000).AsParallel()...
Range 迭代器必须在某个变量中保存其当前状态。如果这个状态从多个线程访问,如何避免竞态条件?以下是我的发现:
1. Enumerable.Range()
返回一个 IEnumerable<int>
。这个可枚举对象的 GetEnumerator()
将为不同的线程返回不同的枚举器。这似乎是使用 yield return
关键字生成的枚举器的内置特性。Reflector 是我的见证。证明链接。
然而,每个枚举器 并非 线程安全的,并且没有任何锁定代码。
2. AsParallel()
只调用一次 GetEnumerator()
,然后从多个线程使用它,因此上述保护措施不起作用。
3. 微软的 Stephen Toub 表示,由于 IEnumerable
本身就不是线程安全的,PLINQ 已经内置了锁定机制。
4. 根据 Reflector,这似乎是在 PartitionedDataSoruce<T>.MoveNext()
方法中实现的。
所以,放轻松吧。你的枚举器可以并且将会是线程不安全的,PLINQ 已经有了自己的锁来处理这个问题。