При автоматическом распараллеливании понимания списка
ИМХО, в силе автоматическая парализация паролей понимания списка была бы невозможна без дополнительной информации (например, предоставляемой с использованием директив в OpenMP) или ее ограничения довыражения, которые включают только встроенные типы / методы.
Если нет гарантии того, что обработка, выполненная для каждого элемента списка, не имеет побочных эффектов, существует вероятность того, что результаты будут недействительными (или, по крайней мере, другими) если выполнено не по порядку.
# Artificial example
counter = 0
def g(x): # func with side-effect
global counter
counter = counter + 1
return x + counter
vals = [g(i) for i in range(100)] # diff result when not done in order
Существует также проблема распределения задач.Как должно быть разложено проблемное пространство?
Если обработка каждого элемента образует задачу (~ ферму задач), то при наличии множества элементов, каждый из которых включает в себя тривиальные вычисления, накладные расходы на управление задачами сводят на нет прирост производительности при распараллеливании.
Можно также использовать подход декомпозиции данных, когда проблемное пространство делится поровну между доступными процессами.
Тот факт, что понимание списков также работает с генераторами, делает это немного хитрым, однако это, вероятно, не ограничитель показа, если накладные расходы на предварительную итерацию его приемлемы.Конечно, существует также возможность генераторов с побочными эффектами, которые могут изменить результат, если последующие элементы будут преждевременно повторяться.Очень маловероятно, но возможно.
Более серьезной проблемой будет дисбаланс нагрузки между процессами.Нет никакой гарантии, что каждому элементу потребуется одинаковое количество времени для обработки, поэтому статически разделенные данные могут привести к тому, что один процесс выполнит большую часть работы, в то время как ваше свободное время не используется.
Разделение списка на более мелкие порции и передача их по мере доступности каждого дочернего процесса является хорошим компромиссом, однако хороший выбор размера порции будет зависеть от приложения, а следовательно, невозможен без дополнительной информации от пользователя.
Альтернативы
Как уже упоминалось в нескольких других ответах, существует множество подходов и параллельных вычислительных модулей / каркасов на выбор в зависимости от одного требования.
ИмеяЯ использовал только MPI (в C) без опыта использования Python для параллельной обработки, я не могу поручиться за любого (хотя, при быстром сканировании, многопроцессорная , кувшин , pp и pyro выделяются).
Если требуется придерживаться как можно ближе к списку понимания, то jug кажетсябудь ближе всехИз учебника распределение задач по нескольким экземплярам может быть простым:
from jug.task import Task
from yourmodule import process_data
tasks = [Task(process_data,infile) for infile in glob('*.dat')]
В то время как это делает что-то похожее на multiprocessing.Pool.map()
, jug
может использовать разные серверные части для синхронизации процессаи хранение промежуточных результатов (redis, filesystem, in-memory), что означает, что процессы могут охватывать узлы в кластере.