Как мне указать многоядерной/многопроцессорной машине обрабатывать вызовы функций в цикле параллельно?

StackOverflow https://stackoverflow.com/questions/56769

  •  09-06-2019
  •  | 
  •  

Вопрос

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

Многие из наиболее интенсивных операций ведут себя детерминировано и пригодны для параллельной обработки.

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

Я прочитал документ Google MapReduce, и хотя я мог бы использовать общий принцип в ряде мест, я пока не буду ориентироваться на большие кластеры, скорее это будет одна многоядерная или многопроцессорная машина для версии 1.0. .Поэтому в настоящее время я не уверен, смогу ли я на самом деле использовать библиотеку, или мне придется самому создавать упрощенную базовую версию.

Я нахожусь на ранней стадии процесса проектирования и пока что в качестве своих языков я ориентируюсь на C-something (для критических по скорости) и Python (для критических для производительности).Если будут веские причины, возможно, перейду, но пока своим выбором доволен.

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

Это было полезно?

Решение

Возможно, я что-то здесь упускаю, но с использованием pthreads это кажется довольно простым.

Создайте небольшой пул потоков с N потоками и один поток будет управлять ими всеми.

Главный поток просто находится в цикле и делает что-то вроде:

  1. Получить фрагмент данных из БД
  2. Найти следующую свободную тему. Если свободных тем нет, подождите.
  3. Передача чанка в рабочий поток
  4. Вернитесь назад и получите следующий фрагмент из БД.

Тем временем рабочие потоки сидят и делают:

  1. Отметить себя как свободный
  2. Подождите, пока главный поток передаст мне порцию данных.
  3. Обработка фрагмента данных
  4. Отметить себя снова свободным

Метод, с помощью которого вы это реализуете, может быть таким же простым, как два массива, управляемых мьютексом.В одном из них указаны обработанные потоки (пул потоков), а в другом указано, свободен или занят каждый соответствующий поток.

Настройте N по своему вкусу...

Другие советы

Что ж, если .net является вариантом, они приложили много усилий для этого. Параллельные вычисления.

Если вы все еще планируете использовать Python, возможно, вам захочется взглянуть на Обработка.Он использует процессы, а не потоки для параллельных вычислений (благодаря Python GIL) и предоставляет классы для распределения «рабочих элементов» по ​​нескольким процессам.Используя класс пула, вы можете написать код, подобный следующему:

import processing

def worker(i):
    return i*i
num_workers = 2
pool = processing.Pool(num_workers)
result = pool.imap(worker, range(100000))

Это параллельная версия itertools.imap, которая распределяет вызовы по процессам.Вы также можете использовать методы пула apply_async и хранить объекты отложенных результатов в списке:

results = []
for i in range(10000):
    results.append(pool.apply_async(worker, i))

Для получения дополнительной информации см. документация класса Pool.

Ошибки:

  • обработка использует fork(), поэтому на Win32 нужно быть осторожным
  • объекты, передаваемые между процессами, должны быть разборчивыми
  • если рабочие работают относительно быстро, вы можете настроить размер фрагмента, т.е.количество рабочих элементов, отправленных рабочему процессу в одном пакете
  • обработка. Пул использует фоновый поток

Вы можете реализовать алгоритм от Google Уменьшение карты без наличия физически отдельных машин.Просто считайте, что каждый из этих «машин» - «потоками». Поток автоматически распределяется на многоядерных машинах.

Если вы работаете с компилятором, который его поддерживает, я бы предложил взглянуть на http://www.openmp.org Для способа аннотирования вашего кода таким образом, что определенные циклы будут параллелизированы.

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

На их веб-странице сообщается, что, например, gcc4.2 будет поддерживать openmp.

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

Я разработал библиотеку MapReduce для многопоточного/многоядерного использования на одном сервере.Обо всем позаботится библиотека, и пользователю остается только реализовать Map и уменьшить.Она позиционируется как библиотека Boost, но пока не принята в качестве формальной библиотеки.Проверить http://www.craighenderson.co.uk/mapreduce

Возможно, вам будет интересно изучить код libdispatch, который является реализацией Apple Grand Central Dispatch с открытым исходным кодом.

Intel TBB или boost::mpi также могут вас заинтересовать.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top