Pythonシリアル演算、パラレル演算、マルチスレッド、マルチプロセス比較実験
3641 ワード
Pythonはマルチコアプロセッサの性能を発揮できない(GILに制限されているそうで、ロックされているのは1つのCPUコアしか使えない、これについてはここに記事がある)が、Pythonのmultiprocessing(マルチプロセス)モジュールやパラレル演算モジュール(例えばpprocess)でマルチコアに使用できる.
テストコードは以下の通りで、プログラムはシリアル演算、パラレル演算、マルチスレッドとマルチプロセスが同じ関数を実行するのにかかる時間をそれぞれテストした.
実行結果は次のとおりです.
[root@localhost test]# python test.py
62.452934 s for traditional, serial computation.
20.665276 s for parallel computation.
64.835923 s for multithreading computation.
18.392281 s for multiprocessing computation.
テスト結果から,並列演算とマルチプロセス計算の速度はシリアル計算とマルチスレッド計算よりも著しく速いことが明らかになった.
ここで質問ですが、なぜマルチスレッドの時間がシリアル単一スレッドより少ないのでしょうか(64.873760>62.452934).
私たちの通常の経験によると、マルチスレッドは単一スレッドよりも速いに違いありません.なぜテスト結果はそうではありませんか.
前述したように、Pythonは1つのCPUコアしか使用できないため、マルチスレッドであっても同じ時間にCPUは1つのスレッド演算しか処理できず、複数のスレッドは並列に動作せず、交代で切り替えて実行される.
したがって、マルチスレッドは、スレッドにデータダウンロードがあり、データの戻りを待つ間にスレッドがブロックされるなど、スレッドにブロックが発生する場合にのみ意味があり、CPUは他のスレッドの演算を処理することができる.
上記のテストプログラムのtakeuptime()関数はブロックされず、演算を続けているので、マルチスレッドとシングルスレッドの効果は同じです(スレッド切り替えにも時間がかかるので、このときマルチスレッドがかかる場合はシングルスレッドよりも多くなります).
並列演算とマルチプロセス演算が速いのは,複数のCPUコアを同時に利用し,複数のデータ演算を同時に行うことができるからである.
takeuptime()関数をブロックに変更し、テストします.
新しい実行結果は次のとおりです.
[root@localhost test]# python test.py
39.996438 s for traditional, serial computation.
10.003863 s for parallel computation.
10.003480 s for multithreading computation.
10.008936 s for multiprocessing computation.
ブロックされたデータ処理中にマルチスレッドの役割が顕著であることがわかる.
テストコードは以下の通りで、プログラムはシリアル演算、パラレル演算、マルチスレッドとマルチプロセスが同じ関数を実行するのにかかる時間をそれぞれテストした.
#! /usr/local/bin/python2.7
# test.py
import time
import pprocess # linux
import threading
from multiprocessing import Process
def takeuptime(n):
chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
s = chars * 1000
for i in range(10*n):
for c in chars:
s.count(c)
if __name__ == '__main__':
list_of_args = [1000, 1000, 1000, 1000]
# Serial computation
start = time.time()
serial_results = [takeuptime(args) for args in list_of_args]
print "%f s for traditional, serial computation." % (time.time() - start)
# Parallel computation
nproc = 4 # maximum number of simultaneous processes desired
results = pprocess.Map(limit=nproc, reuse=1)
parallel_function = results.manage(pprocess.MakeReusable(takeuptime))
start = time.time()
# Start computing things
for args in list_of_args:
parallel_function(args)
parallel_results = results[:]
print "%f s for parallel computation." % (time.time() - start)
# Multithreading computation
nthead = 4 # number of threads
threads = [threading.Thread(target=takeuptime, args=(list_of_args[i],)) for i in range(nthead)]
start = time.time()
# Start threads one by one
for thread in threads:
thread.start()
# Wait for all threads to finish
for thread in threads:
thread.join()
print "%f s for multithreading computation." % (time.time() - start)
# Multiprocessing computation
process = []
nprocess = 4 # number of processes
for i in range(nprocess):
process.append(Process(target=takeuptime, args=(list_of_args[i],)))
start = time.time()
# Start processes one by one
for p in process:
p.start()
# Wait for all processed to finish
for i in process:
p.join()
print "%f s for multiprocessing computation." % (time.time() - start)
実行結果は次のとおりです.
[root@localhost test]# python test.py
62.452934 s for traditional, serial computation.
20.665276 s for parallel computation.
64.835923 s for multithreading computation.
18.392281 s for multiprocessing computation.
テスト結果から,並列演算とマルチプロセス計算の速度はシリアル計算とマルチスレッド計算よりも著しく速いことが明らかになった.
ここで質問ですが、なぜマルチスレッドの時間がシリアル単一スレッドより少ないのでしょうか(64.873760>62.452934).
私たちの通常の経験によると、マルチスレッドは単一スレッドよりも速いに違いありません.なぜテスト結果はそうではありませんか.
前述したように、Pythonは1つのCPUコアしか使用できないため、マルチスレッドであっても同じ時間にCPUは1つのスレッド演算しか処理できず、複数のスレッドは並列に動作せず、交代で切り替えて実行される.
したがって、マルチスレッドは、スレッドにデータダウンロードがあり、データの戻りを待つ間にスレッドがブロックされるなど、スレッドにブロックが発生する場合にのみ意味があり、CPUは他のスレッドの演算を処理することができる.
上記のテストプログラムのtakeuptime()関数はブロックされず、演算を続けているので、マルチスレッドとシングルスレッドの効果は同じです(スレッド切り替えにも時間がかかるので、このときマルチスレッドがかかる場合はシングルスレッドよりも多くなります).
並列演算とマルチプロセス演算が速いのは,複数のCPUコアを同時に利用し,複数のデータ演算を同時に行うことができるからである.
takeuptime()関数をブロックに変更し、テストします.
def takeuptime(n):
def download(url):
# simulate downloading
time.sleep(2)
for i in range(5):
html = download('http://www.redicecn.com/page%d.html' % i)
新しい実行結果は次のとおりです.
[root@localhost test]# python test.py
39.996438 s for traditional, serial computation.
10.003863 s for parallel computation.
10.003480 s for multithreading computation.
10.008936 s for multiprocessing computation.
ブロックされたデータ処理中にマルチスレッドの役割が顕著であることがわかる.