Используя хеш-таблицу в Параллели. ForEach?

Вот проект, который я нашел: https://github.com/google/mysql-protobuf

Это sql, который говорит на protobuf, выглядит многообещающе, но последний коммит был в середине марта 2016.

7
задан Vin 1 November 2009 в 18:20
поделиться

4 ответа

Вы ищете System.Collections.Concurrent.ConcurrentDictionary . Новые параллельные коллекции используют значительно улучшенные механизмы блокировки и должны превосходно работать в параллельных алгоритмах.

Изменить: результат может выглядеть следующим образом:

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

Слово предупреждения: , если элементы в элементах не все имеют уникальный item.Key , тогда SomeIntensiveOperation может быть вызван дважды для этого ключа. В этом примере ключ не передается в SomeIntensiveOperation , но это означает, что код «Сделать что-нибудь со значением» может выполнять пары ключ / значениеA и ключ / значениеB, и только один результат будет сохранен в кеш (не обязательно первый, вычисленный SomeIntensiveOperation). Вы' d потребуется параллельная ленивая фабрика для обработки этого , если это проблема. Кроме того, по очевидным причинам SomeIntensiveOperation должен быть потокобезопасным.

18
ответ дан 6 December 2019 в 06:50
поделиться

Используйте 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;
}
3
ответ дан 6 December 2019 в 06:50
поделиться

проверьте пространство имен System.Collections.Concurrent Я думаю, вам понадобится ConcurrentDictionary

4
ответ дан 6 December 2019 в 06:50
поделиться

Я не вижу другого правильного выбора, кроме как использовать (более или менее явные) блокировки (синхронизированная хеш-таблица просто отменяет все методы с блокировками).

Другой вариант - позволить словарю выйти из синхронизации. Состояние гонки не повредит словарь, ему просто потребуется код для выполнения некоторых лишних вычислений. Профилируйте код, чтобы проверить, не оказывает ли блокировка или отсутствие мемоизации худший эффект.

1
ответ дан 6 December 2019 в 06:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: