Параллельный доступ для чтения в массиве int []: это безопасно? Это быстро?

на четырехъядерной машине я рассматриваю распараллеливание алгоритма C# / .NET, который включает в себя одновременное чтение нескольких потоков небольшого массива int []. Пока он работает довольно хорошо, но я не уверен, где указано, что параллельные чтения в массиве являются потокобезопасными .Сеть. Какие-нибудь указания?

тогда мне также интересно, действительно ли этот подход эффективен? Существуют ли ситуации, когда вам лучше фактически дублировать входные данные для каждого потока, так что нет никакого параллельного чтения, и каждый массив (возможно?) получает возможность кэшироваться рядом с Affinity CPU?

любые мысли о лучших практиках в отношении многоядерных процессоров?

7 ответов


в вашем случае одновременное чтение через Ваш массив будет потокобезопасным.

Что касается эффективности ваших алгоритмов, в зависимости от размера вашего массива, если он будет вписываться в кеш, вы можете увидеть отличную производительность, так как многоядерные эффективно "борются" за кеш в CPU. Если они борются за заполнение кэша одной и той же информацией, они будут делиться значением большего количества обращений к кэшу и лучшей производительности.

предполагая, что Ваш массив вписывается в кэш...


Я не думаю, что есть проблема с параллельных чтений. Это может быть проблематично, если есть параллельные пишет, хотя.

неизменяемые данные по своей сути потокобезопасны.


нет причин не читать содержимое массива одновременно, предполагая, что содержимое никогда не изменится. Нет проблемы параллелизма, поэтому нет необходимости копировать.

Я сомневаюсь, что вы можете многое сделать, чтобы сделать это быстрее.


Это не должно вас беспокоить. Параллельное чтение не является проблемой. Любое количество потоков может одновременно считывать одну и ту же память.


Если на карту поставлены производительность и параллелизм .NET, я бы рекомендовал попробовать написать этот конкретный алгоритм в F#. Компилятор F# будет генерировать .NET код, который имеет 2-6 лучшую производительность.


Thread-safety является проблемой только при обновлении данных. Если у вас несколько параллельных потоков обновление массив вам придется обернуть обновления (и читает, если обновления не являются атомарными) в механизме синхронизации. Для структуры данных только для чтения параллелизм не является проблемой.


оператор присваивания не является потокобезопасным.

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

однако, если существует писатель, который пишет новые ценности, вы уязвимы для состязания.

основная проблема заключается в следующем: читатель начинает читать целое число. Значение загружается из памяти в регистр. В этот момент читатель переключается. Этот затем writer обновляет значение в памяти. Затем читатель переключается обратно и действует на значение, которое он загрузил, - которое больше не является правильным.

Это означает, что такие вещи, как if() не работают надежно. Например,

if( int_array[5] == 10 )
{
}

может вызвать, когда в памяти стоимостью int_array[5] больше не 10.

Я верю в C#, у вас должен быть доступ к Interlocked*() вызовы функций, такие как InterlockedCompareAndSwap(). Эти позволят вам легко достигнуть безопасности потока в этом случай.