プロセス
Python のマルチスレッドは実際にはマルチスレッドではなく、マルチコア CPU のリソースを最大限に活用したい場合、Python では多くの場合複數(shù)のプロセスを使用する必要があります。 Python は非常に使いやすいマルチプロセッシング パッケージを提供しており、関數(shù)を定義するだけで、その他はすべて Python が実行します。このパッケージを使用すると、単一プロセスから同時実行への変換を簡単に実行できます。マルチプロセッシングは、サブプロセス、通信、データの共有をサポートし、さまざまな形式の同期を?qū)g行し、プロセス、キュー、パイプ、ロックなどのコンポーネントを提供します。
1. クラス Process
プロセス クラスを作成します: Process([group [, target [, name [, args [, kwargs]]]]])
target は呼び出し元オブジェクトを表します
args は呼び出し元オブジェクトの位置パラメータタプルを表します
kwargs は呼び出し元オブジェクトの辭書を表します
name はエイリアスです
group は基本的には使用されません
関數(shù)を作成し、それを複數(shù)のプロセスとして使用する例を見てみましょう:
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- import multiprocessing import time def worker(interval, name): print(name + '【start】') time.sleep(interval) print(name + '【end】') if __name__ == "__main__": p1 = multiprocessing.Process(target=worker, args=(2, '兩點水1')) p2 = multiprocessing.Process(target=worker, args=(3, '兩點水2')) p3 = multiprocessing.Process(target=worker, args=(4, '兩點水3')) p1.start() p2.start() p3.start() print("The number of CPU is:" + str(multiprocessing.cpu_count())) for p in multiprocessing.active_children(): print("child p.name:" + p.name + "\tp.id" + str(p.pid)) print("END!!!!!!!!!!!!!!!!!")
出力結(jié)果:
Multiple出力結(jié)果を処理する
2. クラスにプロセスを作成する
#もちろん、次の例のように、プロセスをクラスに作成することもできます。 start() を呼び出すと、自動的に run() メソッドが呼び出されます。
# -*- coding: UTF-8 -*- import multiprocessing import time class ClockProcess(multiprocessing.Process): def __init__(self, interval): multiprocessing.Process.__init__(self) self.interval = interval def run(self): n = 5 while n > 0: print("當前時間: {0}".format(time.ctime())) time.sleep(self.interval) n -= 1 if __name__ == '__main__': p = ClockProcess(3) p.start()
出力結(jié)果は以下の通りです:
プロセスクラスの作成
3.デーモン屬性
知りたいのはデーモン屬性は次の目的で使用されます。次の 2 つの例を見てください。1 つはデーモン屬性を追加したもの、もう 1 つは追加しなかったものです。出力結(jié)果を比較してください:
デーモン屬性を追加しない例:
# -*- coding: UTF-8 -*- import multiprocessing import time def worker(interval): print('工作開始時間:{0}'.format(time.ctime())) time.sleep(interval) print('工作結(jié)果時間:{0}'.format(time.ctime())) if __name__ == '__main__': p = multiprocessing.Process(target=worker, args=(3,)) p.start() print('【EMD】')
出力結(jié)果:
【EMD】 工作開始時間:Mon Oct 9 17:47:06 2017 工作結(jié)果時間:Mon Oct 9 17:47:09 2017
上記の例では、プロセス p はデーモン屬性を追加します:
# -*- coding: UTF-8 -*- import multiprocessing import time def worker(interval): print('工作開始時間:{0}'.format(time.ctime())) time.sleep(interval) print('工作結(jié)果時間:{0}'.format(time.ctime())) if __name__ == '__main__': p = multiprocessing.Process(target=worker, args=(3,)) p.daemon = True p.start() print('【EMD】')
出力結(jié)果:
【EMD】
出力結(jié)果によると、デーモン屬性がが子プロセスに追加されると、メインプロセスが終了すると、子プロセスも終了します。したがって、子プロセスに関する情報は出力されません。
4. 結(jié)合メソッド
上記の例を続けて、子スレッドの実行を終了させたい場合はどうすればよいでしょうか?
次に、join メソッドを使用します。join メソッドの主な機能は、join メソッドを呼び出すプロセスが実行されるまで現(xiàn)在のプロセスをブロックし、その後、現(xiàn)在のプロセスの実行を継続することです。
結(jié)合メソッドを追加する例を見てください:
import multiprocessing import time def worker(interval): print('工作開始時間:{0}'.format(time.ctime())) time.sleep(interval) print('工作結(jié)果時間:{0}'.format(time.ctime())) if __name__ == '__main__': p = multiprocessing.Process(target=worker, args=(3,)) p.daemon = True p.start() p.join() print('【EMD】')
出力結(jié)果:
工作開始時間:Tue Oct 10 11:30:08 2017 工作結(jié)果時間:Tue Oct 10 11:30:11 2017 【EMD】
5、Pool
多數(shù)の子プロセスが必要な場合、1つずつ作成する必要がありますか?
もちろんそうではありません。プロセス プール方式を使用して子プロセスをバッチで作成することもできます。
例は次のとおりです:
# -*- coding: UTF-8 -*- from multiprocessing import Pool import os, time, random def long_time_task(name): print('進程的名稱:{0} ;進程的PID: {1} '.format(name, os.getpid())) start = time.time() time.sleep(random.random() * 3) end = time.time() print('進程 {0} 運行了 {1} 秒'.format(name, (end - start))) if __name__ == '__main__': print('主進程的 PID:{0}'.format(os.getpid())) p = Pool(4) for i in range(6): p.apply_async(long_time_task, args=(i,)) p.close() # 等待所有子進程結(jié)束后在關(guān)閉主進程 p.join() print('【End】')
出力結(jié)果は次のとおりです:
主進程的 PID:7256 進程的名稱:0 ;進程的PID: 1492 進程的名稱:1 ;進程的PID: 12232 進程的名稱:2 ;進程的PID: 4332 進程的名稱:3 ;進程的PID: 11604 進程 2 運行了 0.6500370502471924 秒 進程的名稱:4 ;進程的PID: 4332 進程 1 運行了 1.0830621719360352 秒 進程的名稱:5 ;進程的PID: 12232 進程 5 運行了 0.029001712799072266 秒 進程 4 運行了 0.9720554351806641 秒 進程 0 運行了 2.3181326389312744 秒 進程 3 運行了 2.5331451892852783 秒 【End】
ここで注意すべき點が 1 つあります: 結(jié)合を呼び出す Pool オブジェクト() メソッドは、すべての子プロセスが実行されるまで待機します。完了しました。join() を呼び出す前に close() を呼び出す必要があります。close() を呼び出した後は、新しいプロセスの追加を続けることはできません。
出力結(jié)果に注意してください。子プロセス 0、1、2、3 はすぐに実行されますが、子プロセス 4 は前の子プロセスの完了を待ってから実行されます。プールのデフォルトのサイズは、私のコンピューターでは 4 なので、最大 4 つのプロセスが同時に実行されます。これはプールの意図的な設(shè)計上の制限であり、オペレーティング システムの制限ではありません。これを
p = Pool(5)
に変更すると、5 つのプロセスを同時に実行できます。
6. プロセス間通信
プロセスは必ず通信する必要があり、オペレーティング システムには、プロセス間通信を?qū)g現(xiàn)するための多くのメカニズムが用意されています。 Python のマルチプロセッシング モジュールは、基礎(chǔ)となるメカニズムをラップし、キューやパイプなど、データを交換するための複數(shù)の方法を提供します。
Queue を例として、親プロセス內(nèi)に 2 つの子プロセスを作成します。1 つはキューにデータを書き込み、もう 1 つはキューからデータを読み取ります。
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- from multiprocessing import Process, Queue import os, time, random def write(q): # 寫數(shù)據(jù)進程 print('寫進程的PID:{0}'.format(os.getpid())) for value in ['兩點水', '三點水', '四點水']: print('寫進 Queue 的值為:{0}'.format(value)) q.put(value) time.sleep(random.random()) def read(q): # 讀取數(shù)據(jù)進程 print('讀進程的PID:{0}'.format(os.getpid())) while True: value = q.get(True) print('從 Queue 讀取的值為:{0}'.format(value)) if __name__ == '__main__': # 父進程創(chuàng)建 Queue,并傳給各個子進程 q = Queue() pw = Process(target=write, args=(q,)) pr = Process(target=read, args=(q,)) # 啟動子進程 pw pw.start() # 啟動子進程pr pr.start() # 等待pw結(jié)束: pw.join() # pr 進程里是死循環(huán),無法等待其結(jié)束,只能強行終止 pr.terminate()
出力結(jié)果は次のとおりです。
リーリー