Python学習【365日チャレンジ!】225日目のマスターU(@Udemy11)です。
最近釣りにいってもタチウオが1匹とかアジが数匹とかしか釣れなかったので、冷凍してまとめて料理しようと思っていました。
とりあえず夕食分くらいには溜まったので、アジとタチウオ、セイゴ(スズキのちいさいの)を素揚げして、南蛮漬けを作りました。
アジは中途半端な大きさだったので、骨がきついかなと思ったのですが、酢を多めに入れて一晩おいたら、骨はそんなに気にならなず美味しく食べることができました。
南蛮漬けは、素揚げよりちょっとだけ手間をかけた料理なので、自分で作るとほんとおいしいんですよね。
もちろん、クックパッドなしでは作れませんけど。。。
それでは、今日もPython学習をはじめましょう。
昨日の復習
昨日は、プロセス同士のデータのやり取りをするプロセス間通信の基本を学習しました。
スレッドの場合はスレッドが使うメモリは共有されて、保存したデータもスレッド間で同じものを利用していました。
プロセスの場合は、それぞれのプロセスがそれぞれのメモリを使うので、同じ変数名でもコピーされて別々のデータとして取り扱われていました。
スレッドとプロセスの基本的な違いについては、昨日の記事をごらんください。
今日は、親子でデータのやり取りができるパイプ(Pipe)について学習します。
Pipe
昨日学習したように、マルチプロセスは別々のメモリを使うので、基本はデータを共有しませんが、入力、出力が対になったプロセスでデータの入出力ができるものにPipe
があります。
コマンドラインで使う|(パイプ)
は、コマンドの入出力を別のコマンドに引き渡す処理をしますが、マルチプロセスでは、親子間の橋渡しの役割を持っています。
import logging
import multiprocessing
import time
logging.basicConfig(
level=logging.DEBUG, format='%(processName)s: %(message)s'
)
def func(conn):
conn.send(['test', 1, 2])
time.sleep(2)
conn.close
if __name__ == '__main__':
parent_conn, child_conn = multiprocessing.Pipe()
p = multiprocessing.Process(target=func, args=(parent_conn, ))
p.start()
logging.debug(child_conn.recv())
7行目まではこれまでと同じコードです。
15行目でPipe
でparent_conn
とchild_conn
を定義して、16行目でターゲットに関数func
、引数にparent_conn
を代入したプロセスを作成して次の行でプロセスをスタートさせています。
9行目から12行目で実行する関数を定義していますが、send()
メソッドを使いparent_conn
から引数のリストを送って、18行目のロギングの中でrecv()
メソッドを使ってchild_conn
でリストを受け取っています。
12行目では、conn.close
でPipe
を閉じています。
11行目のtime.sleep(2)
は特に必要ありませんが、リスト['test', 1, 2]
を送ってから2秒後にプログラムが終了するように記述しています。
parent_conn
がデータを受け取ると、すぐにchild_conn
にデータが渡されるので、18行目でリストが表示されてから2秒後にプログラムが終了します。
実行結果
MainProcess: ['test', 1, 2] #この行が出力されたあと2秒後に終了する
時系列で考える
Pythonは基本的に上から順番にコードが実行されていきますが、処理があっち行ったりこっち行ったりするので、今どこの処理をしているのか理解してコードを書くことは重要です。
p.start()
によってプロセスが立ち上がるわけですが、関数func
に値が入ったらすぐにchild_conn
で受け取った値を表示しているので、time.sleep(2)
が実行されるのはその後だとか、p.start()
のあとにp.join()
を入れると関数func
が終了するのを待って次の行の処理をするので、受け取った値を表示するのはコードを実行してから2秒後で、同時にプログラムを終了するとか、いろいろ試して時系列でどうなっているのか考えてみましょう。
まー、時系列という言葉自体、もっと長いスパンのことだと思いますが、処理される順序を考えながら、コードを読み解く癖をつけましょう。
それでは、明日もGood Python!