我有运行体内部的密集操作的Parallel.ForEach循环。

的操作可以使用哈希表来存储的值,并且可以为其它连续循环项被重复使用。我添加到Hashtable中密集的操作完成后,下一个循环的项目可以查找在Hashtable和重用的对象,而不是再次运行密集型操作。

不过,因为我使用Parallel.ForEach存在不安全的问题,引起了Hashtable.Add和使用containsKey(密钥)的调用不同步,因为它们可能会并行运行。引入锁可能会导致PERF的问题。

这里的示例代码:

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
}

必须有一些API,属性设置TPL库中,可能会处理这种情况。是否有?

有帮助吗?

解决方案

您正在寻找 System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> 。新的并发集合使用显著改进的锁定机构,应在并行算法excellectly执行。

编辑:结果可能是这样的:

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
} );

提醒一句:如果在items的元素并不都具有独特的item.Key,然后SomeIntensiveOperation可以得到该键的叫了两声。在这个例子中,关键是不能传递给SomeIntensiveOperation,但它意味着,“不要用一些有价值的东西”的代码可以执行键/值a和键/ VALUEB对,结果只有一个会被存储在缓存中(不一定是第一个由SomeIntensiveOperation计算任一)。你需要一个平行懒工厂来处理这个的如果的这是一个问题。此外,出于显而易见的原因SomeIntensiveOperation应该是线程安全的。

其他提示

查看 System.Collections中。并发命名空间,我认为你需要 ConcurrentDictionary

使用一个ReaderWriterLock,这对工作出色的表现,有许多读取和一些是短时间的写入。您的问题似乎符合该规范。

所有读操作会很快运行,并锁定自由,只有一次有人将被阻塞是当写入正在发生的事情,那写只是只要它采取推在一个Hashtable的东西。

ReaderWriterLockSlim上MSDN

我想我会扔了一些代码...

ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();
Hashtable myTable = new Hashtable();
Parallel.ForEach(items, (item, loopState) =>
{
    cacheLock.EnterReadLock();
    MyObject myObj = myTable.TryGet(item.Key);
    cacheLock.ExitReadLock();

    // If the object isn't cached, calculate it and cache it
    if(myObj == null)
    {
       myObj = SomeIntensiveOperation();
       cacheLock.EnterWriteLock();
       try
       {
           myTable.Add(item.Key, myObj);
       }
       finally
       {
           cacheLock.ExitWriteLock();
       }           
    }
    // Do something with myObj
    // some code here
}

static object TryGet(this Hashtable table, object key)
{
    if(table.Contains(key))
        return table[key]
    else
        return null;
}

我认为没有其他的正确选择使用比(更多或更少显式)的锁(A同步的Hashtable只是覆盖与锁的所有方法)。

另一个选项可以是,以允许字典去同步。比赛情况不会损坏的字典,它只是需要的代码做一些多余的计算。配置文件的代码来检查锁定或丢失的memoization是否具有效果更差。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top