Concurrency-in-python-processes-intercommunication
プロセスの相互通信
プロセス相互通信とは、プロセス間でデータを交換することです。 並列アプリケーションを開発するには、プロセス間でデータを交換する必要があります。 次の図は、複数のサブプロセス間の同期のためのさまざまな通信メカニズムを示しています-
さまざまな通信メカニズム
このセクションでは、さまざまな通信メカニズムについて学習します。 メカニズムは以下のとおりです-
キュー
キューはマルチプロセスプログラムで使用できます。 multiprocessing モジュールのQueueクラスは Queue.Queue クラスに似ています。 したがって、同じAPIを使用できます。 Multiprocessing .Queueは、プロセス間の通信のスレッドおよびプロセスセーフFIFO(先入れ先出し)メカニズムを提供します。
例
以下は、マルチプロセッシングのQueueクラスの概念を理解するために、マルチプロセッシングに関するPython公式ドキュメントから取られた簡単な例です。
from multiprocessing import Process, Queue
import queue
import random
def f(q):
q.put([42, None, 'hello'])
def main():
q = Queue()
p = Process(target = f, args = (q,))
p.start()
print (q.get())
if __name__ == '__main__':
main()
出力
[42, None, 'hello']
パイプ
これは、マルチプロセスプログラムのプロセス間で通信するために使用されるデータ構造です。 Pipe()関数は、デフォルトではduplex(two way)であるパイプで接続された接続オブジェクトのペアを返します。 それは次の方法で動作します-
- パイプの両端を表す接続オブジェクトのペアを返します。
- すべてのオブジェクトには、プロセス間で通信するための2つのメソッド(* send()および recv()*)があります。
例
以下は、マルチプロセッシングの* Pipe()*関数の概念を理解するために、マルチプロセッシングに関するPython公式ドキュメントから取られた簡単な例です。
from multiprocessing import Process, Pipe
def f(conn):
conn.send([42, None, 'hello'])
conn.close()
if __name__ == '__main__':
parent_conn, child_conn = Pipe()
p = Process(target = f, args = (child_conn,))
p.start()
print (parent_conn.recv())
p.join()
出力
[42, None, 'hello']
部長
Managerは、すべてのユーザー間で共有情報を調整する方法を提供するマルチプロセッシングモジュールのクラスです。 マネージャオブジェクトは、共有オブジェクトを管理し、他のプロセスがそれらを操作できるようにするサーバープロセスを制御します。 つまり、マネージャーは、異なるプロセス間で共有できるデータを作成する方法を提供します。 以下は、マネージャオブジェクトのさまざまなプロパティです-
- managerの主なプロパティは、共有オブジェクトを管理するサーバープロセスを制御することです。 *別の重要なプロパティは、プロセスが変更したときにすべての共有オブジェクトを更新することです。
例
サーバープロセスでリストレコードを作成し、そのリストに新しいレコードを追加するためにマネージャーオブジェクトを使用する例を次に示します。
import multiprocessing
def print_records(records):
for record in records:
print("Name: {0}\nScore: {1}\n".format(record[0], record[1]))
def insert_record(record, records):
records.append(record)
print("A New record is added\n")
if __name__ == '__main__':
with multiprocessing.Manager() as manager:
records = manager.list([('Computers', 1), ('Histoty', 5), ('Hindi',9)])
new_record = ('English', 3)
p1 = multiprocessing.Process(target = insert_record, args = (new_record, records))
p2 = multiprocessing.Process(target = print_records, args = (records,))
p1.start()
p1.join()
p2.start()
p2.join()
出力
A New record is added
Name: Computers
Score: 1
Name: Histoty
Score: 5
Name: Hindi
Score: 9
Name: English
Score: 3
Managerの名前空間の概念
Manager Classには名前空間の概念があります。これは、複数のプロセスで複数の属性を共有するための簡単な方法です。 名前空間には、呼び出すことができるパブリックメソッドはありませんが、書き込み可能な属性があります。
例
次のPythonスクリプトの例は、メインプロセスと子プロセスでデータを共有するために名前空間を利用するのに役立ちます-
import multiprocessing
def Mng_NaSp(using_ns):
using_ns.x +=5
using_ns.y* = 10
if __name__ == '__main__':
manager = multiprocessing.Manager()
using_ns = manager.Namespace()
using_ns.x = 1
using_ns.y = 1
print ('before', using_ns)
p = multiprocessing.Process(target = Mng_NaSp, args = (using_ns,))
p.start()
p.join()
print ('after', using_ns)
出力
before Namespace(x = 1, y = 1)
after Namespace(x = 6, y = 10)
Ctypes配列と値
マルチプロセッシングモジュールは、共有メモリマップにデータを保存するためのArrayおよびValueオブジェクトを提供します。 Array は共有メモリから割り当てられたctypes配列であり、 Value は共有メモリから割り当てられたctypesオブジェクトです。
あるために、マルチプロセスからプロセス、値、配列をインポートします。
例
次のPythonスクリプトは、プロセス間でデータを共有するためにCtypes配列と値を利用するためのpython docsからの例です。
def f(n, a):
n.value = 3.1415927
for i in range(len(a)):
a[i] = -a[i]
if __name__ == '__main__':
num = Value('d', 0.0)
arr = Array('i', range(10))
p = Process(target = f, args = (num, arr))
p.start()
p.join()
print (num.value)
print (arr[:])
出力
3.1415927
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
順次プロセスの通信(CSP)
CSPは、システムと並行モデルを特徴とする他のシステムとの相互作用を示すために使用されます。 CSPは、メッセージの受け渡しを介して並行プログラムまたはプログラムを記述するためのフレームワークであるため、並行性を記述するのに効果的です。
Pythonライブラリ– PyCSP
CSPにあるコアプリミティブを実装するために、PythonにはPyCSPというライブラリがあります。 非常に簡単に理解できるように、実装を非常に短く読みやすい状態に保ちます。 以下は、PyCSPの基本的なプロセスネットワークです-
上記のPyCSPプロセスネットワークには、Process1とProcess 2の2つのプロセスがあります。 これらのプロセスは、2つのチャネル(チャネル1とチャネル2)を介してメッセージを渡すことにより通信します。
PyCSPのインストール
次のコマンドの助けを借りて、PythonライブラリPyCSPをインストールできます-
pip install PyCSP
例
次のPythonスクリプトは、2つのプロセスを並行して実行する簡単な例です。 それはPyCSP python libabaryの助けを借りて行われます-
from pycsp.parallel import *
import time
@process
def P1():
time.sleep(1)
print('P1 exiting')
@process
def P2():
time.sleep(1)
print('P2 exiting')
def main():
Parallel(P1(), P2())
print('Terminating')
if __name__ == '__main__':
main()
上記のスクリプトでは、 P1 と P2 という2つの関数が作成され、それらをプロセスに変換するために @ process で装飾されています。
出力
P2 exiting
P1 exiting
Terminating