質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
イベントハンドラ

マウスのクリックなどの特定の事象(イベント)が発生した時に実行される処理のことをイベントハンドラと呼びます。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

599閲覧

Python プロセス間通信 コードレビュー依頼

RRR

総合スコア5

イベントハンドラ

マウスのクリックなどの特定の事象(イベント)が発生した時に実行される処理のことをイベントハンドラと呼びます。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

2クリップ

投稿2022/04/08 15:42

前提

Pythonでプロセス間通信を非同期処理とイベントハンドラを用いて
コーディングしてみたのでコードレビューをして頂きたいです。
変数の扱い方やクラス設計の仕方など
どんなことでもいいのでアドバイスがあればお願いします。

動作

  1. mainはworker1のスレッドを走らせイベントが発生するのを待機する
  2. worker1の処理中にイベントを発生させ通知する
  3. mainはイベント通知を受け取り、worker2をスレッドで走らせる

※Workerが増えてもイベントが受け取れる作りにしています。

該当のソースコード

Python

1import threading 2import time 3 4#グローバル変数 5eventhandler = None 6 7class Main: 8 9 #Worker1をスレッドで走らせてイベント発生をひたすら待つ 10 def main(self): 11 event = threading.Event() 12 Worker1(event).start() 13 14 while True: 15 #イベントが発生するかを1秒間だけ待つ 16 event_is_set = event.wait(1) 17 18 #イベントが発生したらイベントハンドラをスレッドで実行 19 if event_is_set: 20 event.clear() 21 eventhandler.start() 22 23class Worker1(threading.Thread): 24 25 def __init__(self, event:threading.Event): 26 threading.Thread.__init__(self) 27 self.event = event 28 29 #override 30 def run(self): 31 for i in range(1,11): 32 print('Worker1 working: ' + str(i) +'[sec]') 33 #5秒たったらイベントを発生させイベントハンドラに格納 34 if i == 5: 35 print('event_set') 36 self.event.set() 37 global eventhandler 38 eventhandler = Worker2() 39 40 time.sleep(1) 41 42class Worker2(threading.Thread): 43 def __init__(self): 44 threading.Thread.__init__(self) 45 46 #override 47 def run(self): 48 for i in range(1,6): 49 print('Worker2 working: ' + str(i) +'[sec]') 50 time.sleep(1) 51 52if __name__ in '__main__': 53 Main().main()

出力

Worker1 working: 1[sec] Worker1 working: 2[sec] Worker1 working: 3[sec] Worker1 working: 4[sec] Worker1 working: 5[sec] event_set Worker2 working: 1[sec] Worker2 working: 2[sec] Worker1 working: 6[sec] Worker1 working: 7[sec] Worker2 working: 3[sec] Worker2 working: 4[sec] Worker1 working: 8[sec] Worker2 working: 5[sec] Worker1 working: 9[sec] Worker1 working: 10[sec]

補足情報(FW/ツールのバージョンなど)

Python 3.10
Windows 10
Visual Studio Code

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2022/04/08 21:23

提示のコードはどういう問題があるんでしょうか
RRR

2022/04/09 00:19

ここのコードはもっとこうした方がいいよなどのアドバイスを頂きたいです。
bsdfan

2022/04/10 00:59

コードではない部分ですが、これをプロセス間通信と呼ぶのは違和感があります。
RRR

2022/04/10 07:49

@bsdfan プロセス間通信と検索すると以下のような説明でした。 「コンピュータ上で実行中のプログラムの間でデータをやり取りするための仕組み。あるプログラムから別のプログラムへデータやメッセージを通知したり、データの提供依頼や処理依頼を行ったり、依頼に対する結果を返したりすることができる。」 今回のコードではMainクラスがWorkerクラスに「処理依頼」をしているのでプロセス間通信に当てはまるのかなと思いました。
bsdfan

2022/04/10 08:41

一般的には、別のプロセスの間での通信を、プロセス間通信と呼ぶことが多いと思います。 (メモリ空間が異なっているなかで、情報をどうやりとりするか)
guest

回答1

0

ベストアンサー

今だと、 Worker1のなかで生成したスレッドをグローバル変数(eventhandler)に渡してから、eventをset。同時にMainの中でeventを監視してeventhandlerをstartしている
→タイミングによってはeventhandlerがNoneの状態でstartさせてしまい失敗する可能性あり。
なのでグローバル変数を使わないようにしてみる

import threading import time class Main: def main(self): event = threading.Event() Worker1(event).start() while True: if event.wait(1): event.clear() Worker2().start() class Worker1(threading.Thread): def __init__(self, event:threading.Event): threading.Thread.__init__(self) self.event = event #override def run(self): for i in range(1,11): print('Worker1 working: ' + str(i) +'[sec]') if i == 5: print('event_set') self.event.set() time.sleep(1) class Worker2(threading.Thread): def __init__(self): threading.Thread.__init__(self) #override def run(self): for i in range(1,6): print('Worker2 working: ' + str(i) +'[sec]') time.sleep(1) if __name__ in '__main__': Main().main()

グローバル変数を使う動機が「Workerが増えてもイベントが受け取れる作りにしています。」ということ?なら
複数のWorkerがイベント受け取れるようにしたいなら、それぞれのWorkerに共通のeventを持たせておく。

import threading import time class Main: def main(self): event = threading.Event() Worker1(event).start() Worker2(event,taskid=1).start() Worker2(event,taskid=2).start() Worker2(event,taskid=3).start() while True: time.sleep(1) class Worker1(threading.Thread): def __init__(self, event:threading.Event): threading.Thread.__init__(self) self.event = event #override def run(self): for i in range(1,11): print('Worker1 working: ' + str(i) +'[sec]') if i == 5: print('event_set') self.event.set() time.sleep(3) time.sleep(1) class Worker2(threading.Thread): def __init__(self, event,taskid): threading.Thread.__init__(self) self.event = event self.taskid = taskid #override def run(self): self.event.wait() for i in range(1,6): print('Worker2 (id:'+str(self.taskid)+ ') working: ' + str(i) +'[sec]') time.sleep(1) if __name__ in '__main__': try: Main().main() except KeyboardInterrupt: pass

投稿2022/04/09 22:40

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

RRR

2022/04/10 07:40

初めに全てのWorkerスレッドを走らせ、スレッド毎にイベント発生を待機する方が、なんだがしっくりきますね。 確かにタイミングによってeventhandlerがNoneになることを考えていませんでした。ご回答頂いたコードだとその問題も解消されてグローバル変数も使わなくて済みますね。また別のタイミングでイベント発生を通知したいときは、event2 = threading.Event() で新たにイベントを発行することにより対応でき、汎用性もあるのでこちらのコードを参考にさせていただきます。丁寧なご回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問