web-dev-qa-db-ja.com

並列ループを書く

簡単な例で並列ループを実行しようとしています。
何が悪いのですか?

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)

コードの問題は、Python 3のWindows環境で実行すると、並列ジョブを実行するためにpythonのnum_coresインスタンスを開きますが、プロセッサのアクティビティは14%ではなく100%である必要があるため(i7-8ロジックコア)、これは当てはまりません。

追加のインスタンスが何も実行しないのはなぜですか?

14
KMA

機能するマルチプロセッシングコードを提供するというリクエストを続けて、 pool_map を使用することをお勧めします(遅延機能が重要でない場合)、python3で作業している場合の例を紹介しますスターマップを使用できることに言及する価値があります。返される結果の順序が入力の順序に対応する必要がない場合は、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)
19
Fanchi

Windowsでは、マルチプロセッシングモジュールは 'spawn'メソッドを使用して複数のpythonインタープリタープロセスを起動します。これは比較的低速です。Parallelはコードの実行について賢く試みます。特に、バッチの実行に約0.5秒かかるようにバッチサイズを調整します( https://pythonhosted.org/joblib/parallel.html のbatch_size引数を参照)。

processInput()関数は非常に高速で実行されるため、複数のpythonインタープリターを起動してコードを並列に実行するよりも、1つのプロセッサーでジョブを順次実行する方が高速であるとParallelが判断します。

サンプルを複数のコアで強制的に実行する場合は、batch_sizeを1000に設定するか、processInput()をより複雑にして実行時間が長くなるようにします。

編集:使用中の複数のプロセスを表示するウィンドウでの作業例(Windows 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))
3
RootTwo