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

Предположим, у вас есть большой несортированный массив длины n, в котором вы хотите найти определенный элемент (пусть элементы этого массива будут уникальными). Поскольку в худшем случае вам придется искать элемент по всему массиву, время выполнения составит O(n). Однако, поскольку большинство процессоров в настоящее время поддерживают несколько ядер (с гиперпоточностью), вы можете использовать несколько потоков для поиска в массиве, чтобы ускорить его. Таким образом, с m ядрами в вашем распоряжении будет 2 млн (независимых) потоков. Если вы делегируете только часть массива каждому потоку, т.е. даете каждому из 2m потоков n/2m элементов массива для обработки, это было бы оптимально. Однако, когда один из потоков 2m находит элемент, другие потоки должны быть остановлены (для сохранения системных ресурсов), поскольку все элементы уникальны, и другие потоки никогда не найдут этот элемент.

Итак, мой вопрос таков: как бы вы искали большой несортированный массив с уникальными элементами с потоками 2m, сводя к минимуму работу, выполняемую вашими потоками, и время выполнения? Какие синхронизированные структуры данных вам понадобятся? Как вы останавливаете другие потоки 2m-1, когда элемент найден?


person asfeynman    schedule 15.10.2018    source источник


Ответы (1)


Вероятно, самым простым способом было бы иметь атомарно-логическое значение (std::atomic<bool> на языке C++) и иметь поток, который находит число, перед выходом присвоив этому логическому значению значение true.

В дополнение к этому, пусть каждый поток разделит свою часть массива на подчасти, чтобы он мог выполнять тесный цикл, ища число в каждой подчасти, затем проверять атомарно-логическое значение, затем повторять, пока не будет закончатся части для проверки. (Причина использования подчастей вместо простой проверки атомарно-логического значения после каждой итерации одного большого цикла for заключается в том, что даже проверка атомарно-логического значения будет довольно затратной из-за проблем с когерентностью кеша, поэтому лучше амортизировать каждый atomic-boolean-check в течение большего количества итераций и компенсировать немного дополнительной/пустой работы в обмен на лучший параллелизм)

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

person Jeremy Friesner    schedule 15.10.2018