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

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

Если это возможно, может ли кто-нибудь привести пример того, как использовать многопроцессорную обработку в классе или функции, вызываемой из более высокого процесса? Спасибо.

Редактировать:

Вот пример - первый работает, но все делается в 1 файле: simplemtexample3.py:

import random
import multiprocessing
import math

def mp_factorizer(nums, nprocs):
    #schtze den prozess
    #print __name__
    if __name__ == '__main__':
        out_q = multiprocessing.Queue()
        chunksize = int(math.ceil(len(nums) / float(nprocs)))
        procs = []
        for i in range(nprocs):

            p = multiprocessing.Process(
                    target=worker,            
                    args=(nums[chunksize * i:chunksize * (i + 1)],
                          out_q))
            procs.append(p)
            p.start()

        # Collect all results into a single result dict. We know how many dicts
        # with results to expect.
        resultlist = []
        for i in range(nprocs):
            temp=out_q.get()
            index =0
            #print temp
            for i in temp:
                resultlist.append(temp[index][0][0:])
                index +=1

        # Wait for all worker processes to finish
        for p in procs:
            p.join()
            resultlist2 = [x for x in resultlist if x != []]
        return resultlist2

def worker(nums, out_q):
    """ The worker function, invoked in a process. 'nums' is a
        list of numbers to factor. The results are placed in
        a dictionary that's pushed to a queue.
    """
    outlist = []

    for n in nums:
        newnumber= n*2
        newnumberasstring = str(newnumber)
        if newnumber:
            outlist.append(newnumberasstring)
    out_q.put(outlist)

l = []
for i in range(80):
    l.append(random.randint(1,8))

print mp_factorizer(l, 4)

Однако, когда я пытаюсь вызвать mp_factorizer из другого файла, он не работает из-за if __name__ == '__main__':

Simplemtexample.py

import random
import multiprocessing
import math

def mp_factorizer(nums, nprocs):
    #schtze den prozess
    #print __name__
    if __name__ == '__main__':
        out_q = multiprocessing.Queue()
        chunksize = int(math.ceil(len(nums) / float(nprocs)))
        procs = []
        for i in range(nprocs):

            p = multiprocessing.Process(
                    target=worker,            
                    args=(nums[chunksize * i:chunksize * (i + 1)],
                          out_q))
            procs.append(p)
            p.start()

        # Collect all results into a single result dict. We know how many dicts
        # with results to expect.
        resultlist = []
        for i in range(nprocs):
            temp=out_q.get()
            index =0
            #print temp
            for i in temp:
                resultlist.append(temp[index][0][0:])
                index +=1

        # Wait for all worker processes to finish
        for p in procs:
            p.join()
            resultlist2 = [x for x in resultlist if x != []]
        return resultlist2

def worker(nums, out_q):
    """ The worker function, invoked in a process. 'nums' is a
        list of numbers to factor. The results are placed in
        a dictionary that's pushed to a queue.
    """
    outlist = []

    for n in nums:
        newnumber= n*2
        newnumberasstring = str(newnumber)
        if newnumber:
            outlist.append(newnumberasstring)
    out_q.put(outlist)

Startsimplemtexample.py

import simplemtexample as smt
import random

l = []
for i in range(80):
    l.append(random.randint(1,8))

print smt.mp_factorizer(l, 4)
2
harbun 29 Янв 2013 в 17:11

2 ответа

Лучший ответ

if __name__ == '__main__' является обязательным (по крайней мере, в Windows), если вы хотите использовать многопроцессорность.

В Windows это работает следующим образом: для каждого рабочего потока, который вы хотите сгенерировать, Windows автоматически запускает основной процесс и все необходимые файлы снова. Однако только первый запущенный процесс называется main . Вот почему блокирование выполнения mt_factorizer с помощью if __name__ == '__main__' не позволяет многопроцессорным процессам создавать бесконечный цикл.

Таким образом, по существу, окна должны читать файл, который содержит работника и все функции, которые он вызывает - для каждого работника. Блокируя mt_factorizer, мы гарантируем, что никакие дополнительные рабочие не будут созданы, в то время как окна все еще могут выполнять рабочих. По этой причине примеры многопроцессорной обработки, в которых весь код содержится в одном файле, блокируют создание рабочих (как это делает mt_factorizer в этом случае) напрямую (но не рабочая функция), поэтому окна все еще могут выполнять рабочую функцию. Если весь код находится в одном файле, и весь файл защищен, никакой рабочий не может быть создан.

Если многопроцессорный код находится в другом классе и вызывается, if __name__ == '__main__' необходимо реализовать непосредственно над вызовом: mpteststart.py

import random
import mptest as smt

l = []
for i in range(4):
    l.append(random.randint(1,8))
print "Random numbers generated"
if __name__ == '__main__':
    print smt.mp_factorizer(l, 4)

Mptest.py

import multiprocessing
import math

print "Reading mptest.py file"
def mp_factorizer(nums, nprocs):

    out_q = multiprocessing.Queue()
    chunksize = int(math.ceil(len(nums) / float(nprocs)))
    procs = []
    for i in range(nprocs):

        p = multiprocessing.Process(
                target=worker,            
                args=(nums[chunksize * i:chunksize * (i + 1)],
                      out_q))
        procs.append(p)
        p.start()

    # Collect all results into a single result dict. We know how many dicts
    # with results to expect.
    resultlist = []
    for i in range(nprocs):
        temp=out_q.get()
        index =0
        #print temp
        for i in temp:
            resultlist.append(temp[index][0][0:])
            index +=1

    # Wait for all worker processes to finish
    for p in procs:
        p.join()
        resultlist2 = [x for x in resultlist if x != []]
    return resultlist2

def worker(nums, out_q):
    """ The worker function, invoked in a process. 'nums' is a
        list of numbers to factor. The results are placed in
        a dictionary that's pushed to a queue.
    """
    outlist = []

    for n in nums:
        newnumber= n*2
        newnumberasstring = str(newnumber)
        if newnumber:
            outlist.append(newnumberasstring)
    out_q.put(outlist)

В приведенном выше коде if __name__ == '__main__' был удален, поскольку он уже находится в вызывающем файле.

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

Reading mptest.py file
random numbers generated
Reading mptest.py file
random numbers generated
worker started
Reading mptest.py file
random numbers generated
worker started
Reading mptest.py file
random numbers generated
worker started
Reading mptest.py file
random numbers generated
worker started
['1', '1', '4', '1']

Многопроцессорная обработка блокируется от бесконечного выполнения, но остальная часть кода все еще выполняется несколько раз (в этом случае генерация случайных чисел). Это не только приведет к снижению производительности, но также может привести к другим неприятным ошибкам. Решение состоит в том, чтобы защитить весь основной процесс от многократного выполнения окнами, если где-то используется многопроцессорная обработка: mptest.py

import random
import mptest as smt

if __name__ == '__main__':  
    l = []
    for i in range(4):
        l.append(random.randint(1,8))
    print "random numbers generated"   
    print smt.mp_factorizer(l, 4)

Теперь все, что мы получаем, это желаемый результат, случайные числа генерируются только один раз:

Reading mptest.py file
random numbers generated
Reading mptest.py file
worker started
Reading mptest.py file
worker started
Reading mptest.py file
worker started
Reading mptest.py file
worker started
['1', '6', '2', '1']

Обратите внимание, что в этом примере mpteststart.py является основным процессом. Если это не так, if __name__ == '__main__' необходимо перемещать вверх по вызывающей цепочке, пока он не будет в основном процессе. Как только основной процесс будет защищен таким образом, больше не будет нежелательного повторного выполнения кода.

2
harbun 30 Янв 2013 в 11:15

Windows не хватает os.fork. Так что в Windows, модуль многопроцессорной обработки запускает новый интерпретатор Python и (повторно) импортирует скрипт, который вызывает multiprocessing.Process.

Цель использования if __name__ == '__main__' - защитить вызов multiprocessing.Process от повторного вызова при повторной импорте сценария. (Если вы не защитите его, вы получите вилочную бомбу.)

Если вы вызываете multiprocessing.Process из класса или функции , которая не будет вызываться при повторном импорте сценария , тогда проблем не будет. Просто продолжайте и используйте multiprocessing.Process как обычно.

1
unutbu 29 Янв 2013 в 13:37