プロセス
Python のマルチスレッドは実際にはマルチスレッドではなく、マルチコア CPU のリソースを最大限に活用したい場合、Python では多くの場合複数のプロセスを使用する必要があります。 Python は非常に使いやすいマルチプロセッシング パッケージを提供しており、関数を定義するだけで、その他はすべて Python が実行します。このパッケージを使用すると、単一プロセスから同時実行への変換を簡単に実行できます。マルチプロセッシングは、サブプロセス、通信、データの共有をサポートし、さまざまな形式の同期を実行し、プロセス、キュー、パイプ、ロックなどのコンポーネントを提供します。
1. クラス Process
プロセス クラスを作成します: Process([group [, target [, name [, args [, kwargs]]]]])
target は呼び出し元オブジェクトを表します
args は呼び出し元オブジェクトの位置パラメータタプルを表します
kwargs は呼び出し元オブジェクトの辞書を表します
name はエイリアスです
group は基本的には使用されません
関数を作成し、それを複数のプロセスとして使用する例を見てみましょう:
#!/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!!!!!!!!!!!!!!!!!")
出力結果:
Multiple出力結果を処理する
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()
出力結果は以下の通りです:
プロセスクラスの作成
3.デーモン属性
知りたいのはデーモン属性は次の目的で使用されます。次の 2 つの例を見てください。1 つはデーモン属性を追加したもの、もう 1 つは追加しなかったものです。出力結果を比較してください:
デーモン属性を追加しない例:
# -*- coding: UTF-8 -*- import multiprocessing import time def worker(interval): print('工作开始时间:{0}'.format(time.ctime())) time.sleep(interval) print('工作结果时间:{0}'.format(time.ctime())) if __name__ == '__main__': p = multiprocessing.Process(target=worker, args=(3,)) p.start() print('【EMD】')
出力結果:
【EMD】 工作开始时间:Mon Oct 9 17:47:06 2017 工作结果时间: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('工作结果时间:{0}'.format(time.ctime())) if __name__ == '__main__': p = multiprocessing.Process(target=worker, args=(3,)) p.daemon = True p.start() print('【EMD】')
出力結果:
【EMD】
出力結果によると、デーモン属性がが子プロセスに追加されると、メインプロセスが終了すると、子プロセスも終了します。したがって、子プロセスに関する情報は出力されません。
4. 結合メソッド
上記の例を続けて、子スレッドの実行を終了させたい場合はどうすればよいでしょうか?
次に、join メソッドを使用します。join メソッドの主な機能は、join メソッドを呼び出すプロセスが実行されるまで現在のプロセスをブロックし、その後、現在のプロセスの実行を継続することです。
結合メソッドを追加する例を見てください:
import multiprocessing import time def worker(interval): print('工作开始时间:{0}'.format(time.ctime())) time.sleep(interval) print('工作结果时间:{0}'.format(time.ctime())) if __name__ == '__main__': p = multiprocessing.Process(target=worker, args=(3,)) p.daemon = True p.start() p.join() print('【EMD】')
出力結果:
工作开始时间:Tue Oct 10 11:30:08 2017 工作结果时间:Tue Oct 10 11:30:11 2017 【EMD】
5、Pool
多数の子プロセスが必要な場合、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() # 等待所有子进程结束后在关闭主进程 p.join() print('【End】')
出力結果は次のとおりです:
主进程的 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 つあります: 結合を呼び出す Pool オブジェクト() メソッドは、すべての子プロセスが実行されるまで待機します。完了しました。join() を呼び出す前に close() を呼び出す必要があります。close() を呼び出した後は、新しいプロセスの追加を続けることはできません。
出力結果に注意してください。子プロセス 0、1、2、3 はすぐに実行されますが、子プロセス 4 は前の子プロセスの完了を待ってから実行されます。プールのデフォルトのサイズは、私のコンピューターでは 4 なので、最大 4 つのプロセスが同時に実行されます。これはプールの意図的な設計上の制限であり、オペレーティング システムの制限ではありません。これを
p = Pool(5)
に変更すると、5 つのプロセスを同時に実行できます。
6. プロセス間通信
プロセスは必ず通信する必要があり、オペレーティング システムには、プロセス間通信を実現するための多くのメカニズムが用意されています。 Python のマルチプロセッシング モジュールは、基礎となるメカニズムをラップし、キューやパイプなど、データを交換するための複数の方法を提供します。
Queue を例として、親プロセス内に 2 つの子プロセスを作成します。1 つはキューにデータを書き込み、もう 1 つはキューからデータを読み取ります。
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- from multiprocessing import Process, Queue import os, time, random def write(q): # 写数据进程 print('写进程的PID:{0}'.format(os.getpid())) for value in ['两点水', '三点水', '四点水']: print('写进 Queue 的值为:{0}'.format(value)) q.put(value) time.sleep(random.random()) def read(q): # 读取数据进程 print('读进程的PID:{0}'.format(os.getpid())) while True: value = q.get(True) print('从 Queue 读取的值为:{0}'.format(value)) if __name__ == '__main__': # 父进程创建 Queue,并传给各个子进程 q = Queue() pw = Process(target=write, args=(q,)) pr = Process(target=read, args=(q,)) # 启动子进程 pw pw.start() # 启动子进程pr pr.start() # 等待pw结束: pw.join() # pr 进程里是死循环,无法等待其结束,只能强行终止 pr.terminate()
出力結果は次のとおりです。
リーリー