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

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

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

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

Q&A

解決済

1回答

4438閲覧

Python 非同期 asyncio Semaphore 同時実行数を制限しつつタイムアウトを設けたい

navca

総合スコア44

Python 3.x

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

0グッド

0クリップ

投稿2019/04/19 13:48

編集2019/04/20 02:57

python3.6
下記URLを参考に非同期を勉強しています。
https://qiita.com/icoxfog417/items/07cbf5110ca82629aca0
同時実行数を三つに制限しつつタイムアウトを設け、なおかつ処理が終了したものからすぐに出力したいです。
以下にやってみましたが、タイムアウトが発生したところでタスクのスケジュールがストップしてしまう?様な動きになってしまい、ループを回しても次の値を取得することができません。

#結果 [5, 5, 2, 3, 5, 5, 6, 5, 4] 2seconds waited <generator object as_completed.<locals>._wait_for_one at 0x7fc604e89eb8> <generator object as_completed.<locals>._wait_for_one at 0x7fc604e893b8> <generator object as_completed.<locals>._wait_for_one at 0x7fc604e89eb8> <generator object as_completed.<locals>._wait_for_one at 0x7fc604e893b8> <generator object as_completed.<locals>._wait_for_one at 0x7fc604e89eb8> <generator object as_completed.<locals>._wait_for_one at 0x7fc604e893b8> <generator object as_completed.<locals>._wait_for_one at 0x7fc604e89eb8> <generator object as_completed.<locals>._wait_for_one at 0x7fc604e893b8> #終了
35 async def outer(): 36 sem = asyncio.Semaphore(3) 37 async def slp(num): 38 await asyncio.sleep(num) 39 return f'{num}seconds waited' 40 41 42 async def main(num): 43 with await sem: 44 return await slp(num) 45 ran = [random.randint(1,6) for _ in range(9)] 46 print(ran) 47 seq = [asyncio.ensure_future(main(i)) for i in ran] 48 gen = asyncio.as_completed(seq, timeout=4) 49 for s in gen: 50 try: 51 i = await s 52 print(i) 53 except concurrent.futures._base.TimeoutError: 54 print(s) 59 loop = asyncio.get_event_loop() 60 loop.run_until_complete(outer())

https://docs.python.org/ja/3/library/asyncio-sync.html#asyncio.Semaphore
上記に

これらの同期プリミティブのメソッドはtimeout 引数を受け入れません。asyncio.wait_for()タイムアウトして操作を実行するには、この関数を使用します。

とあったので

47 seq = [asyncio.wait_for(main(i), timeout=4) for i in ran] 48 gen = asyncio.as_completed(seq) 49 for s in gen: 50 try: 51 i = await s 52 print(i) 53 except concurrent.futures._base.TimeoutError: 54 print(s) 55 try: 56 gen.__next__() 57 except StopIteration: 58 pass asyncio.ensure_future => [asyncio.wait_for(main(i), timeout=4)) asyncio.as_completed(seq, timeout=4) => asyncio.as_completed(seq) genを次に進めるつもりでgen__next__() #そもそもループしてるので意味ないと思いますが

に変更してみましたが、

[2, 4, 5, 2, 1, 2, 3, 4, 5] 2seconds waited 2seconds waited <generator object as_completed.<locals>._wait_for_one at 0x7f44210dab48> <generator object as_completed.<locals>._wait_for_one at 0x7f44210da938> <generator object as_completed.<locals>._wait_for_one at 0x7f44210dab48> <generator object as_completed.<locals>._wait_for_one at 0x7f44210da938> Task exception was never retrieved future: <Task finished coro=<wait_for() done, defined at /usr/lib64/python3.6/asyncio/tasks.py:321> exception=TimeoutError()> Traceback (most recent call last): File "/usr/lib64/python3.6/asyncio/tasks.py", line 362, in wait_for raise futures.TimeoutError() concurrent.futures._base.TimeoutError Task exception was never retrieved future: <Task finished coro=<wait_for() done, defined at /usr/lib64/python3.6/asyncio/tasks.py:321> exception=TimeoutError()> Traceback (most recent call last): File "/usr/lib64/python3.6/asyncio/tasks.py", line 362, in wait_for raise futures.TimeoutError() concurrent.futures._base.TimeoutError Task exception was never retrieved future: <Task finished coro=<wait_for() done, defined at /usr/lib64/python3.6/asyncio/tasks.py:321> exception=TimeoutError()> Traceback (most recent call last): File "/usr/lib64/python3.6/asyncio/tasks.py", line 362, in wait_for raise futures.TimeoutError() concurrent.futures._base.TimeoutError

今度はリストの最初のデータから処理することさえしていないような動きになってしまいます。(追記:これは勘違いでした。理解できました。)処理順は特にこだわりません。
as_completed,Semaphore,タイムアウトを同居させる方法はあるでしょうか?
よろしくお願いいたします。

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

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

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

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

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

guest

回答1

0

自己解決

https://github.com/aio-libs/async-timeout
↑こちらを利用させていただきました。

with await sem:   async with timeout(4):    return await slp(num) #結果 [4, 6, 4, 2, 1, 5, 5, 2, 1] <generator object as_completed.<locals>._wait_for_one at 0x7f2f7db1e620> <generator object as_completed.<locals>._wait_for_one at 0x7f2f7db1e678> <generator object as_completed.<locals>._wait_for_one at 0x7f2f7db1e620> 1seconds waited 2seconds waited <generator object as_completed.<locals>._wait_for_one at 0x7f2f7db1e678> 2seconds waited <generator object as_completed.<locals>._wait_for_one at 0x7f2f7db1e678> 1seconds waited #合計時間 0:00:09.014896

投稿2019/04/20 10:19

編集2019/04/20 12:05
navca

総合スコア44

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問