この記事で分かること
- 別プロセス(サブプロセス)が必要な場合が分かる
- Pythonプログラムで別プロセス(サブプロセス)を作成する方法が分かる
Pythonで別プロセスを起動する概要
この記事では、Pythonを使った「新規プロセス」を作成方法を紹介します。「新規のプロセス」とは、メインの処理とは異なるサブのプロセスのことです。
では、なぜ、新規のプロセスが作る必要があるのでしょうか?
例えば、チャットのメッセージに対して応答するボットシステムのようなシステムを考えてみましょう。ここで、メインの処理は、随時発生するメッセージへの応答になります。加えて、正午になるとボットが自発的に「正午」をお知らせする機能を追加しようとした場合、チャットメッセージへの応答の処理とは別に、正午を測るタイマーの処理が必要になります。このような場合に、メインの処理である「メッセージ応答の処理」から、「正午を知らせるタイマー処理」は、別にプロセス(サブプロセス)を分けなくてはなりません。
また、メイン処理である「メッセージ応答の処理」とサブプロセスである「正午を知らせるタイマー処理」は、同期していない(一方が他方の結果を待たない)ことから、これらの処理は「非同期である」と言います。
つまり、メインとなる処理とは別に、タイマーなど時間を基準に実行する処理や、常駐して何かを監視する処理をプログラムする場合には、「別プロセス化」が有効になります。
Pythonで別プロセスを起動する環境
Pythonでサブプロセス作成と非同期処理の実行方法の環境は、下の記事で説明している私の環境と同じ環境で確認しています。
レンタルサーバなどのLinuxサーバを使っている場合は、下の記事でプログラミングする環境の作り方を説明しています。
もし、まだプログラムする環境ができていない方は、先にこちらの記事を読んで、プログラミングできる環境をつくることをおすすめします。
Pythonで別プロセスを起動するサンプルプログラム
ここでは、別プロセス(サブプロセス)を作成する方法が分かるプログラムと、別プロセスで動作していることが分かるプログラムをサンプルプログラムとして説明します。その後サンプルプログラムを実行して結果を考察します。
別プロセスを起動するサンプルプログラムの作成
メインとなるプロセスから別プロセス(サブプロセス)を作成し、それぞれが異なるプロセスとなっていることが分かるサンプルプログラムを説明します。サンプルプログラムは次の順番で説明します。
- 別プロセス作成の為のライブラリのインポート
- 別プロセスを作成する関数の定義
- 分けたプロセス側で処理する関数の定義
- 定義した関数の呼び出し処理
1.別プロセス作成の為のライブラリのインポート
ここでは、必要なライブラリの読み込みを行います。プロセスIDを確認するために、「os」というライブラリを、サブプロセス作成のために、「Process」というライブラリをインポートしています。
import os
from multiprocessing import Process
- ライブラリ「os」をインポートする。
- ライブラリ「multiprocessing」からライブラリモジュール「Process」をインポートする。
2.別プロセスを作成する関数の定義
ここでは、別プロセス(サブプロセス)を作成する処理を説明します。これから作成するサブプロセスとプロセスIDを比較するために、プロセスIDを取得して表示しています。サブプロセス作成には、「Process」というライブラリを使用します。
# サブプロセスを生成し、開始する
def create_another_process():
# プロセスIDを取得
pid = os.getpid()
print('process1:'+str(pid))
# サブプロセスを生成する
p = Process(target=execute_anothoer_process, args=("Message: call execute_anothoer_process()!",))
# サブプロセスを開始する
p.start()
- 関数「create_another_process」を定義宣言する。
- 変数「pid」を「os」ライブラリの関数「getpid」で得られたプロセスIDで初期化する。
- 変数「pid」の内容を表示する。
- 「execute_anothoer_process」というサブプロセスを実行する関数名を引数に「Process」を呼び出すことでサブプロセスを扱うオブジェクトが得られ、そのオブジェクトで変数「p」を初期化する。
- インスタンス「p」に対して、サブプロセスの処理を開始する。
3.分けたプロセス側で処理する関数の定義
次に、サブプロセス側で動作する処理をプログラムします。元の親プロセスか引き継いだ文字列を標準出力に表示します。正常にサブプロセスが動作しているのかを確認するために、サブプロセス側のプロセスIDを、print文で表示するようにしています。
# サブプロセスの処理
def execute_anothoer_process(txt):
# 元のプロセスから引き継いだ文字列を表示
print(txt)
# プロセスIDを取得
pid = os.getpid()
print('process2:'+str(pid))
- 関数「execute_anothoer_process」を定義宣言する。
- 引数「text」の内容を表示する。
- 変数「pid」を「os」ライブラリの関数「getpid」で得られたプロセスIDで初期化する。
- 変数「pid」の内容を表示する。
4.定義した関数の呼び出し処理
ここでは、上記で定義したサブプロセス作成関数の呼び出しを行います。
ここでプログラムされているのは、関数「create_another_process」を呼び出す処理は、メインの(元の)プロセスです。関数「create_another_process」から呼び出された関数「execute_anothoer_process」での処理が、別プロセス(サブプロセス)になります。
つまり、関数「create_another_process」を呼び出している処理と、関数「execute_anothoer_process」を実行している処理は、プロセス的に「切り離されて」います。
これは、例えば、関数「execute_anothoer_process」の処理が永遠に終わらなかったとしても、関数「create_another_process」を実行している処理は、プロセス作成後、自由に処理をすすめることができるということを意味します。
逆に言うと、関数「execute_anothoer_process」の処理が永遠に終わらなかったとしても、関数「create_another_process」を実行している処理には関係ない ということを意味するので、メインの処理から切り離された関数「execute_anothoer_process」が正常に終わる設計になっているか確認する必要があります。このような考え方を「スレッドセーフ」と言います。
if __name__ == '__main__':
# サブプロセスを生成し、開始する
create_another_process()
関数「create_another_process」を呼び出す。
別プロセスを起動するサンプルプログラム実行結果
ここでは、上で説明したプログラムしたサンプルプログラムを、「subprocess_test.py」という名前のファイルに纏めて、実行した結果を示します。サンプルプログラムは大きく次のような処理で構成されています。
- 「別プロセスを作成する処理」
- 「別プロセスで実行する処理」
- 「Mainファイルからの実行」
「別プロセスを作成する処理」は、メインのプロセス」です。メインのプロセスでは、「Message: call execute_anothoer_process()!」という文字列を作成したサブプロセス関数へ渡します。
一方、「別プロセスで実行する処理」は、サブプロセスで実行される処理のことです。メインのプロセスから受け取った文字列を、サブプロセスで表示するようにプログラムしています。
また、元のメインプロセスと作成したプロセスの違いを把握するために、プロセス番号を表示するようにしました。これによって、下記の結果のように、異なるプロセス番号が表示され、作成元のプロセスから作成先のプロセスに、文字列が渡っていることが分かります。この文字列ように、あるプロセスから別のプロセスへある値を渡す通信のことを「プロセス間通信」と呼びます。
$ python subprocess_test.py
process1:308
Message: call execute_anothoer_process()!
process2:309
Pythonのその他「初心者向け」技術
この記事では、Pythonを使った「新規プロセス」を作成方法を説明しました。プロセス作成以外にもPythonプログラムには「基礎知識」があります。この基礎知識をを下記の記事にまとめています。
それぞれの記事には、実行可能なサンプルプログラムを掲載しています。
記事を読んで、実際に自分で書いてみてプログラムの動作をご自身で確認することができます。
是非、下記の記事を読んで、「知識」としてだけではなく、「手」でPythonを覚えていってください。