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

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

新規登録して質問してみよう
ただいま回答率
85.48%
マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

Python

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

Q&A

1回答

2861閲覧

pythonでマルチスレッドを裏で起動させながらyieldができない

tam1006

総合スコア28

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

Python

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

0グッド

0クリップ

投稿2020/11/11 07:38

前提

Pythonで2つのクラスを作成し,そのうちの一つをマルチスレッドで起動させるというテストコードがあります。Test1をマルチスレッドとして,ずっと1を出力しています。
そしてinput()で適当なタイミングで入力すると,Test2のstop関数を呼び出して,2を表示したあとに一旦yield でその関数を中断し,そのあとTest.join()でマルチスレッドを止めます。
その後,再度input()で適当なタイミングで入力すると,Test2.stop()が途中から開始されて,4が表示され,yield で中断してmainのwhile文の上に戻ると思っています。
つまり,このコードで期待される動きは大体次のようなものであると思っています。(join()するときに2と4の間に1が出るかでないかは分からないですが,大体このようなものという想定です)

期待される出力

1 1 1 1 1 1 1 ←ここでinput()を入れる 2 (ここでTest1.join()でマルチスレッドを閉じる = 1の出力が止まる) ←ここでinput()を入れる 4 1(whileループの上に戻る) 1 1 1 1 1

問題点

しかし,このような出力にはなりません。
実行すると,常に1が表示され,2が表示されません。というか,Test2.stop()が呼び出されていません。
しかし,Test2.stop()内のyieldをコメントアウトすると,Test2.stop()が呼び出されて2が表示されます。(当然この場合2と4が順繰りに永遠表示され続けますが.)

質問したいのは,なぜマルチスレッドで裏で何かのクラスを起動させている際に.他の,関数内にyieldを含んでいる関数を呼び出すと,その関数が呼び出されないのかということです。
現在マルチスレッドを勉強していて,このようなコードを書くとどうなるのだろうと思って書いてみたら,想定通りの動作にならずに理由が全く分からなかったので質問させて頂きました。

該当のソースコード

python

1import cv2 2import threading 3from threading import Thread 4 5class Test1(threading.Thread): 6 def run(self): 7 while True: 8 print(1) 9 cv2.waitKey(500) 10class Test2: 11 def stop(self): 12 while True: 13 print(2) 14 yield 3 15 print(4) 16 yield 5 17 18if __name__ == '__main__': 19 test1 = Test1() 20 test2 = Test2() 21 while True: 22 test1.start() 23 input() 24 test2.stop() 25 test1.join() 26 input() 27 test2.stop()

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

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

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

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

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

guest

回答1

0

スレッドは関係ありません。yieldの認識が間違っています。

なんとなくyieldを「関数の処理を中断する文」と理解しているようですが、yieldは「ジェネレータ関数において、次の値を返す文」であり、結果的に処理が中断されているだけです。
もっとも、こんな説明では理解できないと思いますので、「ジェネレータ」について調べてみてください。

一応、軽く説明します。

例えば、以下のような関数があったとします。

python

1def gen(): 2 print('1') 3 yield 'first' 4 print('2') 5 yield 'second' 6 print('3')

この関数を呼ぶと、関数の中の処理は実行されず、ジェネレータが作成されます。

>>> n = gen() >>> print(n) <generator object gen at 0x7f22a03d4820> >>>

(本来は、ジェネレータ関数は「iter(gen())」と呼び出すのが正しいです)

作成されたジェネレータをnext関数に渡して呼び出すと、関数の中の最初のyield文まで実行され、yield文で指定された値が返ってきます。

>>> print('return %s.' % repr(next(n))) 1 return 'first'. >>>

続けて呼び出すと、前回のyield文から次のyield文まで実行され、次のyield文で指定された値が返ってきます。

>>> print('return %s.' % repr(next(n))) 2 return 'second'. >>>

最後まで実行されると、StopIteration例外が発生します。

>>> print('return %s.' % repr(next(n))) 3 Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration >>>

このように、yield文を含む関数はジェネレータとして処理しなければなりません。
今回、そこまでしてyield文を使うべきかどうかは疑問ですが、とりあえずジェネレータについて理解した上で判断してください。

投稿2020/11/11 12:05

katsuko

総合スコア3469

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

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

katsuko

2020/11/11 12:12

自分で自分にツッコミを入れるのもなんだけど、 > (本来は、ジェネレータ関数は「iter(gen())」と呼び出すのが正しいです) 正しいのかなぁ…。まぁこの辺はツッコまないでください。
bsdfan

2020/11/11 15:28 編集

ツッコまないでくださいに、ツッコむのもなんですが、ジェネレータはイテレータなので、iter()は不要だと思います。 たいていのイテレータオブジェクトはiter()に対してselfを返すように作られていると思うので、問題はないことが多いと思いますが。 g = gen() print(id(g), id(iter(g))) で同じidになります。
katsuko

2020/11/11 15:38

やっぱりそうですよね…、ただ闇雲に「iter()を呼ぶべし」と覚えていたので書いた後にあっているか不安になって…。 ツッコミありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問