Используйте Python pool.map, чтобы несколько процессов выполняли операции со списком - PullRequest
3 голосов
/ 24 декабря 2011

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

from multiprocessing import Pool

files = ['a','b','c','d','e','f']

def convert(file):
    process_file = files.pop()
    print process_file

if __name__ == '__main__':

    pool = Pool(processes=6)
    pool.map(convert,range(6))

Ожидаемый результат должен быть:

a
b
c
d
e
f

Вместо этого вывод:

f
f
f
f
f
f

Что происходит? Заранее спасибо.

Ответы [ 2 ]

4 голосов
/ 24 декабря 2011

Частично проблема заключается в том, что вы не имеете дело с многопроцессорной природой пула (обратите внимание, что в Python многопоточность не достигает производительности из-за глобальной блокировки интерпретатора).

Существует ли причина, по которой вынужно изменить оригинальный список?Ваш текущий код не использует передаваемую итерацию, а вместо этого редактирует общий изменяемый объект, который является ОПАСНЫМ в мире параллелизма.Простое решение заключается в следующем:

from multiprocessing import Pool

files = ['a','b','c','d','e','f']

def convert(aFile):
    print aFile

if __name__ == '__main__':

    pool = Pool() #note the default will use the optimal number of workers
    pool.map(convert,files)

Ваш вопрос действительно заставил меня задуматься, поэтому я немного углубился в изучение того, почему Python ведет себя таким образом.Кажется, что Python делает некоторую интересную чёрную магию и копирует (при этом поддерживает нестандартный идентификатор) объекта в новый процесс.Это можно увидеть, изменив число или используемые процессы:

from multiprocessing import Pool

files = ['d','e','f','a','b','c',]

a = sorted(files)
def convert(_):
    print a == files
    files.sort()
    #print id(files) #note this is the same for every process, which is interesting

if __name__ == '__main__':

    pool = Pool(processes=1) #
    pool.map(convert,range(6))

==> все, кроме первого вызова, выведите «True», как и ожидалось.

Если вы установите число или процессы в2, он менее детерминирован, поскольку зависит от того, какой процесс фактически выполняет свои операторы в первую очередь.

1 голос
/ 23 июля 2018

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

from multiprocessing.dummy import Pool

"решает" проблему, но не защищаетобщая память против одновременного доступа.Вы все равно должны использовать threading.Lock или Queue с put и get

...