Как мне параллельно запускать одну функцию над циклом? Python 2.7.12

#python #parallel-processing

#python #параллельная обработка

Вопрос:

Я пытаюсь распараллелить программу, которая использует одну функцию в цикле for, которая параллельно обновляет глобальный список / переменную. Как мне это сделать и как я могу передать значения функции?

Пример кода выглядит следующим образом,

 #python 2.7.12
import random
sum=0

#sample function to take a random integer between 0 to i and add it to global variable sum
def hello(i):
    print "Thread Id :",i   #instead of i it should be the threadID
    sum=sum random.randrange(0,i)

#main function  
i=1
for i in range(10): 
    hello(i)        #how to parallelize this function over a loop?
  

Редактировать 1 :
Пробовал использовать процесс из многопроцессорной обработки, но не знаю, как передавать значения функциям и как запускать его параллельно в цикле.

 from multiprocessing import Process
sum=0 

def Hello(): 
   print 'hello: starting' 
   sum=sum i    #Don't know how to pass values here 
   print 'hello: finishing' 

if name == 'main': 
   p1 = Process(target=func1) 
   p1.start() 
   p1.join()
   print sum
  

Комментарии:

1. Глобальные переменные и потоки не очень хорошо сочетаются. Было бы намного лучше, если бы hello() возвращалась только случайная часть, а результаты суммировались в главном цикле.

2. @JohnGordon за исключением того, что это процессы, а не потоки. OP: можете ли вы опубликовать multiprocessing код, который вы пробовали?

3. @roganjosh Это код, который я пробовал, из многопроцессорного процесса импорта sum= 0 def func1(): print ‘func1: starting’ sum=sum я #Не знаю, как передавать значения здесь print ‘func1: finishing’ if name == ‘ main ‘: p1 = Process(target=func1) p1.start() p1.join()

4. @ShoebAhmed Пожалуйста, отредактируйте вопрос, чтобы включить код, который вы пробовали, правильно отформатированный. Это неразборчиво как комментарий.

5. @roganjosh Новичок в stackoverflow, пожалуйста, простите мою наивность. Я также добавлю код к вопросу.

Ответ №1:

Вы можете использовать multiprocessing.dummy.Пул, который принимает функцию, за которой следуют ваши параметры (см. Ниже).

Вам также нужно будет беспокоиться о синхронизации вашей глобальной переменной (см. Ниже Пример использования Lock).

Кроме того, если вы не используете «глобальную сумму», сумма внутри вашей функции ссылается на локальную переменную sum (пример глобальной суммы см. Ниже).

threading.current_thread() дает вам идентификатор потока.

 #python 2.7.12
from multiprocessing.dummy import Pool as ThreadPool
import threading
import random

lock = threading.Lock()

sum = 0

#sample function to take a random integer between 0 to i and add it to global variable sum
def hello(i):
    if (i == 0):
        return
    global sum
    print threading.current_thread()   #instead of i it should be the threadID
    r = random.randrange(0,i)
    lock.acquire()
    try:
        sum = sum   r
    finally:
        lock.release()

ThreadPool().map(hello, list(range(1, 11)))

print sum
  

Комментарии:

1. Спасибо за помощь @pscuderi. У меня было несколько вопросов относительно кода,

2. 1. В функции hello(i), почему вы вернули if i == 0? 2. Не могли бы вы объяснить, где именно функция hello() выполняется 10 раз?

3. randrange выдавал исключение, когда i == 0, и я предположил, что в этом случае r может быть только 0, так зачем добавлять его к сумме.

4. ThreadPool().map(привет, список (диапазон (10))) вызывает привет 10 раз, по одному разу для каждого значения в списке, возвращаемого list(диапазон (10)).

Ответ №2:

Передайте параметры в виде кортежа аргументам kwarg функции Process: Вот пример из документации:

 if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()
  

https://docs.python.org/2/library/multiprocessing.html

Также верно и то, что сказал Джон Гордон в своем комментарии. Вам нужно, чтобы главный процесс (который будет запускать цикл) обрабатывал суммирование. То, что вы в основном пытаетесь сделать, — это простое задание map / reduce.

Часть map — это ваша функция hello, а reduce — это сумма. В python есть много примеров выполнения заданий map / reduce.

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

Комментарии:

1. Это запускает один процесс. В документах используется что-то вроде этого (по какой-то неизвестной причине), но он не использует дополнительную мощность от многоядерного процессора

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

3. Вы можете запускать несколько процессов почти так же, как вы это делали, и сначала обрабатывать данные, подлежащие обработке (в виде списка, содержащего отдельные фрагменты или for цикл). Передайте каждому процессу его собственный уникальный фрагмент. Ваш подход отражает документы, но я никогда не понимал, как он обращается к GIL. Я раньше не видел multiprocessing.dummy , поэтому мне нужно разобраться в том, чтобы понять ответ pscuderi.