[解決済み] Pythonのasyncioモジュールを使って並行タスクを正しく作成し、実行するには?
質問
私は、2つの同時実行される
Task
オブジェクトを、Python 3 の比較的新しい
asyncio
モジュールを使っています。
簡単に言うと、asyncioは非同期プロセスや同時並行の
Task
を扱うように設計されているようです。これは
await
(非同期関数で適用)の使用を促進します。イベントループをブロックすることなく、結果を待ち、使用するコールバックフリーな方法として。(フューチャーとコールバックはまだ実行可能な代替手段です)。
また、これは
asyncio.Task()
クラスの特殊なサブクラスである
Future
のサブクラスで、コルーチンをラップするために設計されています。好ましくは
asyncio.ensure_future()
メソッドを使って呼び出すのが望ましいです。asyncioタスクの使用目的は、独立して実行されているタスクが同じイベントループ内で他のタスクと「同時に」実行することを可能にすることです。私の理解では
Tasks
の間にあるコルーチンを自動的に駆動し続けるイベントループに接続されている、ということです。
await
ステートメントの間で自動的にコルーチンを駆動し続けます。
のいずれかを使用する必要がなく、同時実行タスクが使用できるというアイデアが気に入っています。
Executor
クラスのいずれかを使用する必要なく、同時実行タスクが使用できるというアイデアが好きですが、実装に関する詳細な情報はあまり見当たりません。
現在、私がやっている方法はこれです。
import asyncio
print('running async test')
async def say_boo():
i = 0
while True:
await asyncio.sleep(0)
print('...boo {0}'.format(i))
i += 1
async def say_baa():
i = 0
while True:
await asyncio.sleep(0)
print('...baa {0}'.format(i))
i += 1
# wrap in Task object
# -> automatically attaches to event loop and executes
boo = asyncio.ensure_future(say_boo())
baa = asyncio.ensure_future(say_baa())
loop = asyncio.get_event_loop()
loop.run_forever()
ループする2つのタスクを同時に実行しようとした場合、タスクが内部で
await
式がない場合、タスクは
while
ループにはまり、他のタスクの実行を事実上ブロックしてしまいます (通常の
while
ループのように)他のタスクの実行を効果的にブロックします。しかし、タスクが (a) 待機するようになると、問題なく並行して実行されるように見えます。
このように
await
ステートメントは、イベントループにタスク間の切り替えの足場を提供し、同時実行の効果を与えているようです。
内部での出力例
await
:
running async test
...boo 0
...baa 0
...boo 1
...baa 1
...boo 2
...baa 2
出力例
がない場合
内部
await
:
...boo 0
...boo 1
...boo 2
...boo 3
...boo 4
質問
この実装は、"適切な "例として
asyncio
?
のみで動作するということでよろしいでしょうか?
Task
をブロックポイントとして提供すること (
await
式) を提供する必要があるのでしょうか?
どのように解決するのですか?
イベントループ内で実行されているコルーチンは、他のコルーチンやタスクの実行をブロックします。
-
を使用して他のコルーチンを呼び出す。
yield from
またはawait
(Python3.5+を使用している場合) を使用します。 - を返します。
これは、以下の理由からです。
asyncio
がシングルスレッドであるためです。イベントループを実行する唯一の方法は、他のコルーチンがアクティブに実行されないことです。使用方法
yield from
/
await
はコルーチンを一時的に停止させ、イベントループが動作する機会を与えます。
あなたのコード例は素晴らしいものですが、多くの場合、非同期I/Oを行わない長時間実行のコードは、そもそもイベントループの内部で実行させたくないのではないでしょうか。そのような場合、多くの場合、イベントループ内で
asyncio.loop.run_in_executor
を使用してバックグラウンドのスレッドやプロセスでコードを実行する方が理にかなっています。
ProcessPoolExecutor
は、タスクが CPU に依存している場合により良い選択です。
ThreadPoolExecutor
でない I/O を行う必要がある場合に使われます。
asyncio
-でないI/Oが必要な場合に使用されます。
例えば、2つのループは完全にCPUバウンドで、状態を共有しないので、最高のパフォーマンスは
ProcessPoolExecutor
を使用して、各ループを CPU 間で並列に実行することで最高のパフォーマンスを得ることができます。
import asyncio
from concurrent.futures import ProcessPoolExecutor
print('running async test')
def say_boo():
i = 0
while True:
print('...boo {0}'.format(i))
i += 1
def say_baa():
i = 0
while True:
print('...baa {0}'.format(i))
i += 1
if __name__ == "__main__":
executor = ProcessPoolExecutor(2)
loop = asyncio.get_event_loop()
boo = loop.run_in_executor(executor, say_boo)
baa = loop.run_in_executor(executor, say_baa)
loop.run_forever()
関連
-
[解決済み] 小数点以下1桁を取得する[重複]。
-
[解決済み] なぜ(0-6)は-6=偽なのか?重複
-
[解決済み] DataFrameに日付間の日数カラムを追加する pandas
-
[解決済み] 文字列から先頭と末尾のスペースを削除するには?
-
[解決済み] 値で列挙名を取得する [重複]。
-
[解決済み] 範囲指定された浮動小数点数のランダムな配列を生成します。
-
[解決済み] Django 1.7で初期マイグレーションからマイグレートバックする方法は?
-
[解決済み] オブジェクトのリストに特定の属性値を持つオブジェクトが含まれているかどうかをチェックする
-
[解決済み] Pythonでランダムなファイル名を生成する最良の方法
-
[解決済み] 認証プラグイン 'caching_sha2_password' はサポートされていません。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Djangoで2つの日付の間を選択する
-
[解決済み] Pythonの要素別タプル演算(sumなど
-
[解決済み] タプルのリストを複数のリストに変換するには?
-
[解決済み] あるオブジェクトが数であるかどうかを確認する、最もパイソン的な方法は何でしょうか?
-
[解決済み] tensorflowのCPUのみのインストールでダイナミックライブラリ 'cudart64_101.dll' を読み込めなかった
-
[解決済み] Pythonで、ウェブサイトが404か200かを確認するためにurllibをどのように使用しますか?
-
[解決済み] pycharmがタブをスペースに自動変換する
-
[解決済み] Pythonの文字列書式をリストで使う
-
[解決済み] Pythonでランダムなファイル名を生成する最良の方法
-
[解決済み] asyncioで関数を定期的に実行するにはどうしたらいいですか?