回答編集履歴
3
実際のアプリケーションでの事例を追記
test
CHANGED
@@ -257,3 +257,23 @@
|
|
257
257
|
組み込み環境で消費電力が気になる、
|
258
258
|
|
259
259
|
等といった事情でもない限り優先度は低めになると思います。
|
260
|
+
|
261
|
+
|
262
|
+
|
263
|
+
|
264
|
+
|
265
|
+
|
266
|
+
|
267
|
+
----
|
268
|
+
|
269
|
+
追記2: 実際のアプリケーションでの after を用いた queue の読み出し
|
270
|
+
|
271
|
+
|
272
|
+
|
273
|
+
- Tkinter製IDE: IDLE のコード (idlelib.rpc) pollresponse 内で queue.get
|
274
|
+
|
275
|
+
idlelib.pyshell poll_subprojecc内でafter
|
276
|
+
|
277
|
+
- Tkinter製IDE: Thonny のコード (thonny.workbench)
|
278
|
+
|
279
|
+
[_poll_ipc_requests](https://github.com/thonny/thonny/blob/6f429da861b47d1a72d75c64978fc65a26b3ecd4/thonny/workbench.py#L2235)
|
2
コードのフォーマット修正
test
CHANGED
@@ -176,13 +176,17 @@
|
|
176
176
|
|
177
177
|
対策する場合、一度のafterで読み出せる回数に制限を設けます。例)
|
178
178
|
|
179
|
+
```python
|
180
|
+
|
179
181
|
for _ in range(5):
|
180
182
|
|
181
|
-
|
183
|
+
if queue.empty()
|
182
|
-
|
184
|
+
|
183
|
-
|
185
|
+
break
|
184
|
-
|
186
|
+
|
185
|
-
|
187
|
+
...
|
188
|
+
|
189
|
+
```
|
186
190
|
|
187
191
|
|
188
192
|
|
1
queue.get の場合を追記。queue.put とトピックを分離
test
CHANGED
@@ -1,7 +1,15 @@
|
|
1
|
+
# queue.put に関して
|
2
|
+
|
3
|
+
|
4
|
+
|
1
5
|
> サブスレッド->メインスレッドの場合はafter()を使えばいいのでしょうか?
|
2
6
|
|
3
7
|
|
4
8
|
|
9
|
+
追記: queue.get での after に関しては後述
|
10
|
+
|
11
|
+
|
12
|
+
|
5
13
|
after, after_idle で、「対象の関数をメインスレッド側で呼び出させること」はできます。
|
6
14
|
|
7
15
|
大抵の場合、サブスレッド→メインスレッドの queue の代替として使えます。
|
@@ -85,3 +93,163 @@
|
|
85
93
|
例えば、tcl のライブラリを含まずにアプリケーションを配布を想定する場合に、
|
86
94
|
|
87
95
|
問題となる可能性があります。
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
----
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
# queue.get に関して
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
|
113
|
+
> サブスレッドでメッセージをput、メインスレッドでgetする。
|
114
|
+
|
115
|
+
このキューはメインスレッドでafterを常に回すことでgetする、という方法自体(質問文のコード)は問題ないでしょうか。
|
116
|
+
|
117
|
+
|
118
|
+
|
119
|
+
頻度次第です。
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
- OK: queue.get() ではブロッキングの可能性がある為、get_nowait を使う。
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
- afterの呼び出し間隔次第でラグが問題にならない様なら大丈夫です。
|
128
|
+
|
129
|
+
- 間隔が短い(高頻度に呼び出される)事による負荷が、
|
130
|
+
|
131
|
+
実行環境次第で問題になる事はあるかもしれません。
|
132
|
+
|
133
|
+
|
134
|
+
|
135
|
+
100ms 程度(10回/1秒) であれば問題ないと思いますが、
|
136
|
+
|
137
|
+
ユーザーがラグと認識しない程度に増やしても大丈夫です。
|
138
|
+
|
139
|
+
(過剰なケース: 1ms 間隔で呼び出し → 不要な呼び出しが大量発生)
|
140
|
+
|
141
|
+
|
142
|
+
|
143
|
+
|
144
|
+
|
145
|
+
懸念事項:
|
146
|
+
|
147
|
+
- empty() を確認してから get 迄に別の場所で読み取られていた場合、エラーになる。
|
148
|
+
|
149
|
+
現状のコードではマルチスレッドを考慮しなくても良い為、問題なしですが、
|
150
|
+
|
151
|
+
empty は確認せずに、get 時の例外で queue.Empty を捕捉する方が汎用的です。
|
152
|
+
|
153
|
+
|
154
|
+
|
155
|
+
> while not from_sub_to_main.empty():
|
156
|
+
|
157
|
+
|
158
|
+
|
159
|
+
がキューへのputが読み出し速度を上まわる場合、
|
160
|
+
|
161
|
+
実質無限ループとなり、GUIが応答なしとなる原因に成り得ます。
|
162
|
+
|
163
|
+
|
164
|
+
|
165
|
+
質問のコードの頻度の queue.put では問題ありませんが、
|
166
|
+
|
167
|
+
例えば、動画のフレームをqueueでやる取する場合は調整が必要です。
|
168
|
+
|
169
|
+
|
170
|
+
|
171
|
+
ライブラリ化して、汎用的なコードにしたい場合は対策が必要。
|
172
|
+
|
173
|
+
現状のコードでしか使わない実装なら対策不要。
|
174
|
+
|
175
|
+
|
176
|
+
|
177
|
+
対策する場合、一度のafterで読み出せる回数に制限を設けます。例)
|
178
|
+
|
179
|
+
for _ in range(5):
|
180
|
+
|
181
|
+
if queue.empty()
|
182
|
+
|
183
|
+
break
|
184
|
+
|
185
|
+
...
|
186
|
+
|
187
|
+
|
188
|
+
|
189
|
+
---
|
190
|
+
|
191
|
+
after 以外でキューの読み取り手段もありますが、
|
192
|
+
|
193
|
+
お勧めしにくい理由として、サンプルコードをほぼ見かけたことありません。
|
194
|
+
|
195
|
+
出典を出せればよいのですが…
|
196
|
+
|
197
|
+
|
198
|
+
|
199
|
+
- A: サブスレッドで event_generate を使い通知、
|
200
|
+
|
201
|
+
メイン側で bind した任意の関数を呼び出す。
|
202
|
+
|
203
|
+
※ event_generate は thread-safe な関数
|
204
|
+
|
205
|
+
- B: 非同期IO (asyncio) で動かす。
|
206
|
+
|
207
|
+
利点は、Event 等、queue 以外の排他制御の手段が取れる。
|
208
|
+
|
209
|
+
但し、プログラム全体を asyncio に対応させる必要あり。
|
210
|
+
|
211
|
+
- C: createfilehandler を用いた通知
|
212
|
+
|
213
|
+
|
214
|
+
|
215
|
+
解説
|
216
|
+
|
217
|
+
after での実行のように、
|
218
|
+
|
219
|
+
ループで毎回データが届いているか確認する方式を polling といい、
|
220
|
+
|
221
|
+
こういった方式での実装に共通した、問題点・改善方法が知られています。
|
222
|
+
|
223
|
+
上に示した方法は、何れもこの問題を改良・効率化する方法です。
|
224
|
+
|
225
|
+
|
226
|
+
|
227
|
+
after 100ms では、約10回/1秒 程度の頻度での呼び出しですが、
|
228
|
+
|
229
|
+
動画再生等の高頻度のやり取りでもない限り、大半が不要な呼び出しとなります。
|
230
|
+
|
231
|
+
|
232
|
+
|
233
|
+
event_generate では、通知を <Button> 等と同じ GUI のイベントとして得られます。
|
234
|
+
|
235
|
+
asyncio は、(内部でpollingに近いことは行われていますが)より効率的な方法で実装されてます。
|
236
|
+
|
237
|
+
createfilehandler も同様、通知の仕組みの一種です。
|
238
|
+
|
239
|
+
polling とは異なり、通知のタイミングで任意の関数を呼び出せます。
|
240
|
+
|
241
|
+
→ 不要な呼び出し回数を抑制できる。
|
242
|
+
|
243
|
+
|
244
|
+
|
245
|
+
但し、アプリ-ケーション単位で見る場合、
|
246
|
+
|
247
|
+
この部分の改善はユーザ視点では目に見えにくく、
|
248
|
+
|
249
|
+
|
250
|
+
|
251
|
+
ライブラリとして実装していて汎用的な実装にしたい場合や、
|
252
|
+
|
253
|
+
組み込み環境で消費電力が気になる、
|
254
|
+
|
255
|
+
等といった事情でもない限り優先度は低めになると思います。
|