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

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

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

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

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

Q&A

解決済

2回答

457閲覧

Python:threadingの実行結果の保存先について

calendar

総合スコア4

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

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

0グッド

0クリップ

投稿2022/11/15 18:47

以前質問させていただき回答をいただいたのですが、問題をみつけたため質問させていただきます。

実現したいことと前提

ライブラリABC(名前は仮です)のfuncという関数の返り値を1秒以内の時間制限で取得する関数を作りたいです。
具体的には1秒以内で値が返ってきたらその値を出力。
1秒以内に返ってこなければ関数を停止し別の文字列を出力。

func:文字列を返す,実行時間は一瞬で終わることもあれば無限に終わらないこともある

発生している問題・解決方針

ソースコードで指摘している箇所で止まってしまっています。
原因としてはreturn文の箇所でもう一度ABC.funcを実行しなおしているためだと考えています。
スレッドに渡した関数の実行結果をどうにかして保存して置ければ、それをreturnすればよいので解決すると考えています。

該当のソースコード

python

1import threading 2import ABC#ライブラリの名前に意味はないです 3 4#出力結果は文字列 5def thread_func(): 6 txt="hoge" 7 th=threading.Thread(target=ABC.func()) 8 th.start() 9 th.join(1)#1秒間動かす 10 if not th.is_alive():#ABC.funcが停止していればreturnしたい 11 return ABC.func()#ここで停止してしまいます 12 else: 13 return txt 14 15 16

よろしくお願いいたします!

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

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

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

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

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

otn

2022/11/16 05:02

先の質問とは質問の前提がかなり異なっていますが、こっちが本当の要件だったと言うことですかね。
calendar

2022/11/16 16:02

前回はお世話になりました。ありがとうございました。 参考にさせていただいたコードを実現するために別のメソッドを用意しようと思い作成したのがこちらになります。
otn

2022/11/16 16:09

先の質問は、先の質問に書いてあった要件のための物なので、要件が先の質問と異なると言うことなら、全く新たに考えた方が良いです。
guest

回答2

0

ベストアンサー

threading.Threadで呼んだ関数の返り値を受け取ることはできません。 ですが、いくつか方法はあります。

その1

スレッドはメモリを共有していますので、データの受け渡し用にミュータブルなオブジェクトを関数に渡して、そこに値を入れてもらう方法です。
質問の状況で、ライブラリABCの関数変更できないのであれば、ラッパー(wrapper)を作ります。
ABC.func()が修正できるのであれば、そうするのがいいでしょう。

python

1import threading 2import ABC#ライブラリの名前に意味はないです 3 4def wrap_ABCfunc (result): 5 result.append(ABC.func()) 6 7#出力結果は文字列 8def thread_func(): 9 txt = 'hoge' 10 result = [] 11 th=threading.Thread(target=wrap_ABCfunc(), args=(result,)) 12 th.start() 13 th.join(1)#1秒間動かす 14 if not th.is_alive():#ABC.funcが停止していればreturnしたい 15 return result[0] 16 else: 17 return txt

その2

pythonには、threadingよりも新しい、並列処理用のモジュールがいくつかあり、それらを使うと呼び出した関数の返り値を取得することができます。

concurent.futureモジュールだとたぶんこんな感じ

python

1import concurrent.futures 2 3with concurrent.futures.ThreadPoolExecutor() as executor: 4 future = executor.submit(ABC.hoge) 5 try: 6 return_value = future.result(timeout=1) 7 print(return_value) 8 except concurrent.futures._base.TimeoutError as e: 9 print('hoge')

投稿2022/11/16 02:33

TakaiY

総合スコア12781

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

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

calendar

2022/11/16 15:57

コードまで記載いただきありがとうございます。 concurrent.futuresに関して勉強を進め記載いただいたコードを参考にしたところ、 実現したいシステムができました。
guest

0

threading.Thread で target に渡す関数の戻り値は無視されます。
source code 該当箇所 Thread.run メソッド内

値を受け渡す方法は

  • 関数内で何処か外側のスコープに渡すか、Queue 等を使い値を受け渡します。
  • concurrent.futures.ThreadPoolExecutor や ProcessPoolExecutor を使うなら

 関数の結果を取り出す result() メソッドに timeout を指定することができます。

  • 外部ライブラリを使う

 タイムアウト時に例外を投げる関数デコレーターやコンテキストマネージャが幾つか有ります。
Pythonの関数をタイムアウトさせるときに便利なライブラリ

スレッドを用いる方法では、タイムアウトの通知はされますが、関数の実行自体は中断されない点に注意してください。
もし時間の掛かる処理を取りやめたい場合は、関数自体を中断可能な設計するか、
multiprocessing.Process と terminate を用いてプロセス自体を終了することになります。

Python の Thread クラスには明示的に強制終了させる API はありません。
(可能ではありますが、内部API呼び出し等をしたり、デバッグが複雑になりお勧めは出来ません)
また、ProcessPoolExecutor で用いる future の cancel メソッドは、
実行スケジュールのキャンセルであって、実行中の関数はキャンセルできない点にも注意。


ABC.func が止まる件については、ABC.func のコードを提示してください。

Thread(target=ABC.func()) target の時点で関数を呼び出している等、
恐らく実行されているコードと掲載のコードが異なるので、
質問には問題の現象が再現できるコードを掲載してください。

投稿2022/11/16 02:24

編集2022/11/16 02:58
teamikl

総合スコア8664

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

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

calendar

2022/11/16 16:01

丁寧にリンクまで記載いただきありがとうございます。 ProcessPoolExecutorでのfutureのcancelメソッドについての解説もありがとうございます。 そこで一度悩んでしまったのでアンサーを読み返したとき助かりました。
teamikl

2022/11/16 16:56

スレッドやProcessPoolExecutorだけでは 「関数を停止し」の部分が出来ない点に注意してください。 タイムアウトによりメイン側の待機状態は解除されますが、 ABC.func 関数の実行自体は続きます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問