マルチスレッド/マルチプロセスによるタスク処理速度の向上

2416 ワード

バックグラウンドでWebページをキャプチャしたり、オフラインデータ統計など、タスクを完了するには複数回反復する必要があり、毎回ネットワークIO、ディスクIO、データベース接続の待機が発生し、タスクの実行時間が長くなります.しかし、タスクには反復間で順番に実行する必要がないという特徴があります.これは、マルチスレッド/マルチプロセスに非常に適したシーンです.
pythonでは、GILの制限により、本格的なマルチスレッドがないため、ThereadPoolも公式サイトでmultiprocessingの代わりにmultiprocessingを使用するように提示しています.
This module is OBSOLETE and is only provided on PyPI to support old projects that still use it. 
Please DO NOT USE IT FOR NEW PROJECTS! 
Use modern alternatives like the multiprocessing module in the standard library or even an asynchroneous approach with asyncio.

Multiprocessingの簡単な使い方:
from multiprocessing import Pool
def f(x): 
    return x*x
if __name__ == '__main__': 
    with Pool(5) as p: 
        print(p.map(f, [1, 2, 3]))

この方式は、依然として同期シーケンス実行方式を採用しており、マルチプロセスの威力を発揮する非同期方式は以下の通りである.
from multiprocessing import Pool
import time

def f(x):
    time.sleep(1)                                                                                                      
    return x,x*x

if __name__ == '__main__':
    res_list = []  
    # apply  
    with Pool(5) as p:
        for i in xrange(1,20):
            res = pool.apply_async(f,[i])
            res_list.append(res)

    # print
    for res in res_list:
        print(res.get())

    pool.close()
    pool.join()

特に注意しなければならない点はいくつかあります.
  • res.get()は、プロセス呼び出しが完了すると、統一的に取得する必要があります.そうしないと、同期方式
  • になります.
  • pool.join()メインプロセスをすべてのサブプロセスが完了するまで待機させ、
  • を終了する
  • joinの前にpoolを呼び出す必要がある.close()

  • プロセスを直接定義することもできます
    from multiprocessing import Process
    import os
    import time
    
    def info(title):
        print(title)                                                                                                                                                                                           
        print('module name:', __name__)
        print('parent process:', os.getppid())
        print('process id:', os.getpid())
    
    def f(name):
        time.sleep(1)
        info('function f')
        print('hello', name)
    
    if __name__ == '__main__':
        info('main line')
        for i in xrange(10):
            p = Process(target=f, args=(i,))
            p.start()
            # p.join()
    

    コメント:
  • はosを通過する.getppid()とos.getpid()親プロセスおよび現在のプロセスのID
  • を取得する
  • スレッド順序で実行する場合は、p.join()
  • を呼び出すことができる.