次のコマンドを実行すると、これは興味深いメモになります。
import numpy
from multiprocessing import Pool
a = numpy.arange(1000000)
pool = Pool(processes = 5)
result = pool.map(numpy.sin, a)
UnpicklingError: NEWOBJ class argument has NULL tp_new
期待していなかったので、何が起こっているのか:
>>> help(numpy.sin)
Help on ufunc object:
sin = class ufunc(__builtin__.object)
| Functions that operate element by element on whole arrays.
|
| To see the documentation for a specific ufunc, use np.info(). For
| example, np.info(np.sin). Because ufuncs are written in C
| (for speed) and linked into Python with NumPy's ufunc facility,
| Python's help() function finds this page whenever help() is called
| on a ufunc.
はい、numpy.sin は c で実装されているため、マルチプロセッシングで直接使用することはできません。
そのため、別の関数でラップする必要があります
パフォーマンス:
import time
import numpy
from multiprocessing import Pool
def numpy_sin(value):
return numpy.sin(value)
a = numpy.arange(1000000)
pool = Pool(processes = 5)
start = time.time()
result = numpy.sin(a)
end = time.time()
print 'Singled threaded %f' % (end - start)
start = time.time()
result = pool.map(numpy_sin, a)
pool.close()
pool.join()
end = time.time()
print 'Multithreaded %f' % (end - start)
$ python perf.py
Singled threaded 0.032201
Multithreaded 10.550432
うわー、どちらも期待していませんでした。まあ、Python関数を使用している初心者にとっては、ラッパーと純粋なc関数の比較であっても、いくつかの問題があり、値をコピーするオーバーヘッドもあります。デフォルトではマルチプロセッシングはありません。データを共有しないため、各値を前後にコピーする必要があります。
データを適切にセグメント化する場合は、次の点に注意してください。
import time
import numpy
from multiprocessing import Pool
def numpy_sin(value):
return numpy.sin(value)
a = [numpy.arange(100000) for _ in xrange(10)]
pool = Pool(processes = 5)
start = time.time()
result = numpy.sin(a)
end = time.time()
print 'Singled threaded %f' % (end - start)
start = time.time()
result = pool.map(numpy_sin, a)
pool.close()
pool.join()
end = time.time()
print 'Multithreaded %f' % (end - start)
$ python perf.py
Singled threaded 0.150192
Multithreaded 0.055083
マルチプロセッシングは素晴らしいですが、使用方法に応じて、高速な場合と低速な場合があり、常にテストして比較する必要があります...
使用していないことを認めますがnumpy.sin
、実際にマルチプロセッシングが計算を高速化することを最初に確認することをお勧めします。値を前後にコピーするオーバーヘッドが影響する可能性があります。
いずれにせよ、マルチスレッドコードの使用が最良で最も安全な方法であると私は信じています...pool.map
これが役立つことを願っています。