Являются ли операции pu sh и pop для хэшей и массивов atomi c безопасными для потоков? - PullRequest
6 голосов
/ 22 апреля 2020

У меня есть огромный файл данных (около 4T), который мне нужно обработать. Я использую 4 потока на моем 4-ядерном процессоре. Первый поток анализирует первую четверть файла и так далее. Все потоки должны добавить свои результаты к одному и тому же ха sh и одному массиву после того, как они проанализировали разделы своей четверти файла данных. Итак, являются ли операции "pu sh" и "pop", "shift" и "unshift" для ha sh и для массива atomi c безопасными для потоков или я должен прибегнуть к более сложным механизмам, таким как семафоры

1 Ответ

10 голосов
/ 22 апреля 2020

Нет, они не являются ни атомами c, ни поточными, и их использование из нескольких потоков приведет к сбоям или несоответствиям данных. та же структура данных будет плохо масштабироваться при добавлении новых потоков. Это связано с тем, как аппаратное обеспечение работает в условиях параллелизма; кратко:

  • Производительность памяти сильно зависит от кешей
  • Некоторые уровни кеша зависят от ядра ЦП
  • Запись в память означает ее загрузку исключительно в кеш текущего ядра
  • Процесс перемещения его из кэша одного ядра для записи в него является дорогостоящим (штраф в цикле 60-100 баллов)

Вы можете использовать блокировку для достижения правильности . Для этого я не рекомендую работать с блокировкой напрямую, но вместо этого загляните в модуль, подобный OO::Monitors, где вы можете инкапсулировать ha sh в объект и выполнить блокировку на границах.

Если количество нажатий, которые вы делаете в общей структуре данных, мало по сравнению с объемом работы, проделанной для создания элементов в pu sh, то вы можете не ограничиваться блокировкой и конфликтом вокруг структуры данных. Однако, если вы выполняете тысячи push или аналогичных операций в секунду, я предлагаю поискать альтернативный дизайн. Например:

  1. Разбейте работу на части для каждого работника
  2. Используйте start, чтобы выделить каждого работника, который возвращает Promise. Поместите Promise s в массив.
  3. Пусть каждый Promise возвращает массив или ха sh произведенных им элементов.
  4. Объедините результаты каждого из них. Например, если каждый возвращает массив, то my @all-results = flat await @promises; или аналогичного ему достаточно, чтобы собрать все результаты вместе.

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

...