免責事項:私はmultiprocessing
SOとドキュメントに関する多数の回答を確認しましたが、質問が本当に古いか(Python 3.Xはそれ以来多くの改善を行っています)、明確な回答が見つかりませんでした。関連する何かを見逃した可能性がある場合は、正しい方向に向けてください。
Jupyter Notebookを実行しているため、フォルダーモジュールで以下のように定義した単純な関数から始めましたが、競合のためmultiprocessing
、インポートされた関数でのみ実行できるようです。
def f(a):
return a * 100
いくつかのテストデータを作成し、いくつかのテストを実行しました。
from itertools import zip_longest
from multiprocessing import Process, Pool, Array, Queue
from time import time
from modules.test import *
li = [i for i in range(1000000)]
リスト内包表記:本当に速い
start = time()
tests = [f(i) for i in li]
print(f'Total time {time() - start} s')
>> Total time 0.154066801071167 s
ここでのSOの例の回答:11秒程度
start = time()
results = []
if __name__ == '__main__':
jobs = 4
size = len(li)
heads = list(range(size//jobs, size, size//jobs)) + [size]
tails = range(0,size,size//jobs)
pool = Pool(4)
for tail,head in zip(tails, heads):
r = pool.apply_async(f, args=(li[tail:head],))
results.append(r)
pool.close()
pool.join() # wait for the pool to be done
print(f'Total time {time() - start} s')
>>Total time 11.087551593780518 s
そしてProcess
、上記の例に当てはまるかどうかわからないことがあります。私はよく知らないがmultiprocessing
、新しいインスタンスの作成にはいくらかのオーバーヘッドがあることを理解しているが、データが大きくなるにつれて、オーバーヘッドを正当化するはずである。
私の質問は、Python 3.xの現在のパフォーマンスでmultiprocessing
、上記と同様の操作を実行する際に使用していることです。もしそうなら、ワークロードの並列化にどのように適用できますか。
私が読んで理解した例のほとんどは、情報を受信する1つのプロセスに実際のアイドル時間があり、並列化するのが理にかなっている場合のWebスクレイピングに使用されますが、リストや辞書などの計算を実行している場合は、どのようにアプローチする必要がありますか。
あなたの例がうまく機能していない理由は、2つのまったく異なることをしているからです。
リスト内包表記では、の各要素にマッピングf
していますli
。
2番目のケースでは、li
リストをjobs
チャンクに分割job
してから、それらのチャンクのそれぞれに関数の時間を適用します。そして今、ではf
、n * 100
元のリストの約1/4のサイズのチャンクを取り、それを100倍します。つまり、シーケンス反復演算子を使用するため、チャンクの100倍のサイズの新しいリストを作成します。
>>> chunk = [1,2,3]
>>> chunk * 10
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
>>>
つまり、基本的には、リンゴとオレンジを比較しています。
ただし、マルチプロセッシングには、すぐに使用できるマッピングユーティリティがすでに付属しています。これがより良い比較で、foo.pyと呼ばれるスクリプトです。
import time
import multiprocessing as mp
def f(x):
return x * 100
if __name__ == '__main__':
data = list(range(1000000))
start = time.time()
[f(i) for i in data]
stop = time.time()
print(f"List comprehension took {stop - start} seconds")
start = time.time()
with mp.Pool(4) as pool:
result = pool.map(f, data)
stop = time.time()
print(f"Pool.map took {stop - start} seconds")
ここで、実際のパフォーマンス結果をいくつか示します。
(py37) Juans-MBP:test_mp juan$ python foo.py
List comprehension took 0.14193987846374512 seconds
Pool.map took 0.2513458728790283 seconds
(py37) Juans-MBP:test_mp juan$
この非常に些細な関数の場合、プロセス間通信のコストは、関数をシリアルに計算するコストよりも常に高くなります。したがって、マルチプロセッシングによるメリットは見られません。ただし、それほど重要ではない関数は、マルチプロセッシングからの利益を見ることができます。
これは簡単な例です。乗算する前に、マイクロ秒だけスリープします。
import time
import multiprocessing as mp
def f(x):
time.sleep(0.000001)
return x * 100
if __name__ == '__main__':
data = list(range(1000000))
start = time.time()
[f(i) for i in data]
stop = time.time()
print(f"List comprehension took {stop - start} seconds")
start = time.time()
with mp.Pool(4) as pool:
result = pool.map(f, data)
stop = time.time()
print(f"Pool.map took {stop - start} seconds")
そして今、あなたはプロセスの数に見合った利益を見るでしょう:
(py37) Juans-MBP:test_mp juan$ python foo.py
List comprehension took 13.175776720046997 seconds
Pool.map took 3.1484851837158203 seconds
私のマシンでは、1回の乗算にかかる時間はマイクロ秒(約10ナノ秒)よりも桁違いに短いことに注意してください。
>>> import timeit
>>> timeit.timeit('100*3', number=int(1e6))*1e-6
1.1292944999993892e-08
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加