在Parallel.ForEach中使用哈希表?

Vin*_*Vin 7 .net c# parallel-extensions task-parallel-library

我有一个Parallel.ForEach循环在主体内部运行密集操作.

该操作可以使用Hashtable来存储值,并且可以重用于其他连续的循环项.我在密集操作完成后添加到Hashtable,下一个循环项可以在Hashtable中查找并​​重用该对象,而不是再次运行密集操作.

但是,因为我使用的是Parallel.ForEach,所以存在一个不安全的问题,导致Hashtable.Add和ContainsKey(key)调用不同步,因为它们可能并行运行.引入锁可能会导致性能问题.

这是示例代码:

Hashtable myTable = new Hashtable;
Parallel.ForEach(items, (item, loopState) =>
{
    // If exists in myTable use it, else add to hashtable
    if(myTable.ContainsKey(item.Key))
    {
       myObj = myTable[item.Key];
    }
    else
    {
       myObj = SomeIntensiveOperation();
       myTable.Add(item.Key, myObj); // Issue is here : breaks with exc during runtime
    }
    // Do something with myObj
    // some code here
}
Run Code Online (Sandbox Code Playgroud)

TPL库中必须有一些API,属性设置,可以处理这种情况.在那儿?

Sam*_*ell 18

你在找System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>.新的并发集合使用显着改进的锁定机制,并且应该在并行算法中执行得非常好.

编辑:结果可能如下所示:

ConcurrentDictionary<T,K> cache = ...;
Parallel.ForEach(items, (item, loopState) =>
{
    K value;
    if (!cache.TryGetValue(item.Key, out value))
    {
        value = SomeIntensiveOperation();
        cache.TryAdd(item.Key, value);
    }

    // Do something with value
} );
Run Code Online (Sandbox Code Playgroud)

警告的话:如果items所有元素都不具有唯一性item.Key,则SomeIntensiveOperation可以为该键调用两次.在示例中,密钥未传递给SomeIntensiveOperation,但这意味着"使用值执行某些操作"代码可以执行key/valueA和key/valueB对,并且只有一个结果将存储在缓存中(不一定是第一个)由SomeIntensiveOperation计算的一个).如果这是一个问题,你需要一个并行的懒惰工厂来处理它.此外,由于显而易见的原因,SomeIntensiveOperation应该是线程安全的.