Написание параллельного цикла

Я пытаюсь запустить параллельный цикл на простом примере.
Что я делаю неправильно?

from joblib import Parallel, delayed  
import multiprocessing

def processInput(i):  
        return i * i

if __name__ == '__main__':

    # what are your inputs, and what operation do you want to 
    # perform on each input. For example...
    inputs = range(1000000)      

    num_cores = multiprocessing.cpu_count()

    results = Parallel(n_jobs=4)(delayed(processInput)(i) for i in inputs) 

    print(results)

Проблема с кодом заключается в том, что при выполнении в среде Windows в Python 3 он открывает num_cores экземпляры python для выполнения параллельных заданий, но только один активен. Это не должно быть так, так как активность процессора должна быть на 100% вместо 14% (в i7-8 логических ядрах).

Почему лишние экземпляры ничего не делают?

Ответы

Ответ 1

Продолжая по вашему запросу предоставлять рабочий многопроцессорный код, я предлагаю вам использовать pool_map (если отложенная функциональность не важна), я Я приведу вам пример, если вы работаете над python3, стоит упомянуть, что вы можете использовать starmap. Также стоит упомянуть, что вы можете использовать map_sync/starmap_async, если порядок возвращаемых результатов не должен соответствовать порядку входов.

import multiprocessing as mp

def processInput(i):
        return i * i

if __name__ == '__main__':

    # what are your inputs, and what operation do you want to
    # perform on each input. For example...
    inputs = range(1000000)
    #  removing processes argument makes the code run on all available cores
    pool = mp.Pool(processes=4)
    results = pool.map(processInput, inputs)
    print(results)

Ответ 2

В Windows многопроцессорный модуль использует метод "spawn" для запуска нескольких процессов интерпретатора python. Это относительно медленно. Параллельно пытается быть умным при запуске кода. В частности, он пытается настроить размер партии, поэтому для выполнения партии требуется около половины секунды. (См. Аргумент batch_size в https://pythonhosted.org/joblib/parallel.html)

Ваша функция processInput() работает так быстро, что Parallel определяет, что быстрее запускать задания поочередно на одном процессоре, чем разворачивать несколько интерпретаторов python и параллельно запускать код.

Если вы хотите заставить свой пример работать на нескольких ядрах, попробуйте установить batch_size в 1000 или сделать processInput() более сложным, поэтому выполнение займет больше времени.

Изменить: рабочий пример в окнах с несколькими используемыми процессами (я использую окна 7):

from joblib import Parallel, delayed
from os import getpid

def modfib(n):
    # print the process id to see that multiple processes are used, and
    # re-used during the job.
    if n%400 == 0:
        print(getpid(), n)  

    # fibonacci sequence mod 1000000
    a,b = 0,1
    for i in range(n):
        a,b = b,(a+b)%1000000
    return b

if __name__ == "__main__":
    Parallel(n_jobs=-1, verbose=5)(delayed(modfib)(j) for j in range(1000, 4000))