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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python

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

Q&A

解決済

2回答

616閲覧

tornadoでのwhile loopの抜け方

LeonhardThird

総合スコア29

Python

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

0グッド

0クリップ

投稿2023/04/23 13:11

server.pyはPython Web Frameworkであるtornadoを使っています。

client.htmlのプルダウンメニューから選択した銘柄をserver.pyに送り、対応する銘柄をSQLから取得し、client.htmlに送り返すプログラムを作りたい。

SQLが随時更新されるので、def on_messageを(*1)のようにwhile Trueを使って1銘柄のときは随時更新していました。

しかし、(*2)の注意書きを目にしたので、どうやってプルダウンメニューで別の銘柄を選んだ時に前のloopを切断し、新しい銘柄での随時更新情報をclient.htmlに送るのか、どなたか分かる方はいらっしゃいませんでしょうか?
それとも、他の良い方法があるのならばご教授いただければ幸いです。

(*1)

python:server.py

1import psycopg2, os, pandas as pd, time, json, random 2import tornado.websocket 3import tornado.ioloop 4 5class RealTimeDataHandler(tornado.websocket.WebSocketHandler): 6 def open(self): 7 print ('Session Opened. IP:' + self.request.remote_ip) 8 conn = psycopg2.connect( 9 dbname='postgres', 10 user='postgres', 11 password=os.environ.get('PostgreSQL_PASS'), 12 host='localhost', 13 ) 14 self.cur = conn.cursor() 15 16 self.ioloop = tornado.ioloop.IOLoop.instance() 17 18 def get_data_from_sql(self): 19 self.cur.execute("SELECT * FROM public.random_time_multi") 20 m = self.cur.fetchall() 21 column_names = [desc[0] for desc in self.cur.description] 22 data = pd.DataFrame(m, columns=column_names) 23 return data 24 25 def on_message(self, message): 26 column_name = json.loads(message)['symbol'] 27 while True: 28 data = self.get_data_from_sql() 29 message = json.dumps(data[column_name].to_dict()) 30 self.write_message(message) 31 time.sleep(5) 32 33 def on_close(self): 34 print("Session closed") 35 self.cur.close() 36 self.ioloop.stop() 37 38 def check_origin(self, origin): 39 return True 40 41def stop_tornado(): 42 tornado.ioloop.IOLoop.current().stop() 43 44app = tornado.web.Application([(r"/ws/display", RealTimeDataHandler)]) 45 46if __name__ == '__main__': 47 app.listen(8080) 48 try: 49 tornado.ioloop.IOLoop.current().start() 50 except: 51 print("KeyboardInterrupt received. Stopping Tornado.") 52 stop_tornado()

(*2)
on_messageメソッド内で無限ループ(while Trueなど)が実行されている場合、新しいメッセージを受け取ることができません。無限ループが実行されている間は、on_messageメソッドがブロックされてしまい、新しいメッセージを処理するためのイベントループが実行されないためです。

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

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

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

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

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

guest

回答2

0

ベストアンサー

クライアントからsymbolを受け取ったタイミングでtornado.ioloop.PeriodicCallbackを起動し、一定間隔でクライアントへwrite_messageすればよいのではないでしょうか?またはスレッドを生成してそこで無限ループするとか。

投稿2023/04/23 16:42

a.com

総合スコア871

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

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

LeonhardThird

2023/04/24 08:01 編集

tornado.ioloop.PeriodicCallbackを使ってうまくいきました。ありがとうございました。
guest

0

python:server.py

1import psycopg2, os, pandas as pd, time, json, random 2import tornado.websocket 3import tornado.ioloop 4 5class RealTimeDataHandler(tornado.websocket.WebSocketHandler): 6 def open(self): 7 """WebSocket接続が開かれた際の処理を実装 8 """ 9 print ('Session Opened. IP:' + self.request.remote_ip) 10 conn = psycopg2.connect( 11 dbname='postgres', 12 user='postgres', 13 password=os.environ.get('PostgreSQL_PASS'), 14 host='localhost', 15 ) 16 self.cur = conn.cursor() 17 18 self.column_name = None 19 20 # PeriodicCallbackを使って定期的にデータを取得し、クライアントに送信する処理を設定 21 self.periodic_callback = tornado.ioloop.PeriodicCallback(self.send_data_to_client, 5000) # 5000は5000[ms] 22 self.periodic_callback.start() 23 24 def on_message(self, message): 25 self.column_name = json.loads(message)['symbol'] 26 print('RecieveMessage of %s' % self.column_name) 27 28 def get_data_from_sql(self): 29 """SQLからデータを取得する。table 全体を返すようにする。 30 31 Returns: 32 pandas.DataFrame: 33 """ 34 self.cur.execute("SELECT * FROM public.random_time_multi") 35 m = self.cur.fetchall() 36 column_names = [desc[0] for desc in self.cur.description] 37 data = pd.DataFrame(m, columns=column_names) 38 return data 39 40 def send_data_to_client(self): 41 print('send data of %s' % self.column_name) 42 if self.column_name: 43 data = self.get_data_from_sql() 44 message = json.dumps(data[['unix_time', self.column_name]].to_dict()) 45 self.write_message(message) 46 47 def on_close(self): 48 print("Session closed") 49 self.cur.close() 50 self.periodic_callback.stop() 51 52 def check_origin(self, origin): 53 return True 54 55def stop_tornado(): 56 tornado.ioloop.IOLoop.current().stop() 57 58app = tornado.web.Application([(r"/ws/display", RealTimeDataHandler)]) 59 60if __name__ == '__main__': 61 app.listen(8080) 62 try: 63 tornado.ioloop.IOLoop.current().start() 64 except: 65 print("KeyboardInterrupt received. Stopping Tornado.") 66 stop_tornado() 67

投稿2023/04/24 08:00

LeonhardThird

総合スコア29

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問