Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

Python辞典

  1. トップページ
  2. Python辞典
  3. asyncio / async / await

asyncio / async / await

『asyncio』はPython標準の非同期I/Oフレームワークです。『async def』で非同期関数(コルーチン)を定義し、『await』で別のコルーチンの完了を待ちます。スレッドを使わずに単一スレッドでI/O待ち処理を効率よく並行実行でき、多数のHTTPリクエストやファイルI/Oが発生するアプリケーションで特に効果的です

構文
import asyncio

# 非同期関数(コルーチン)の定義
async def my_coroutine():
    await asyncio.sleep(1)  # 非同期で待機
    return 結果

# コルーチンの実行
asyncio.run(my_coroutine())

# 複数コルーチンの並行実行
results = await asyncio.gather(coro1(), coro2(), coro3())
関数・クラス一覧
関数・クラス概要
async def func()非同期関数(コルーチン関数)を定義する。
await 式コルーチン・タスク・Futureの完了を待つ。async def内でのみ使える。
asyncio.run(coro)イベントループを起動してコルーチンを実行する。Python 3.7+。
asyncio.gather(*coros)複数のコルーチンを並行実行して結果のリストを返す。
asyncio.sleep(seconds)非同期で指定秒数待機する(他のコルーチンの実行を妨げない)。
asyncio.create_task(coro)コルーチンをタスクとしてスケジューリングする。
asyncio.wait_for(coro, timeout)タイムアウト付きでコルーチンを実行する。
asyncio.Queue()非同期処理用のFIFOキュー。
サンプルコード
import asyncio
import time

# 基本的な非同期関数
async def say_hello(name, delay):
    await asyncio.sleep(delay)      # この間、他のコルーチンが実行できる
    print(f"こんにちは、{name}!")

async def main():
    # 順次実行(合計3秒)
    await say_hello('田中', 1)
    await say_hello('鈴木', 2)

asyncio.run(main())

# gather: 並行実行(合計2秒、最長のもの)
async def main_parallel():
    start = time.time()
    await asyncio.gather(
        say_hello('田中', 1),
        say_hello('鈴木', 2),
        say_hello('山田', 1.5),
    )
    print(f"合計時間: {time.time() - start:.1f}秒")  # 約2.0秒

asyncio.run(main_parallel())

# create_task: タスクとして即座にスケジューリング
async def fetch_data(url, delay):
    await asyncio.sleep(delay)
    return f"{url} のデータ"

async def main_tasks():
    # タスクとして登録(すぐに開始)
    task1 = asyncio.create_task(fetch_data('https://api1.example.com', 1))
    task2 = asyncio.create_task(fetch_data('https://api2.example.com', 2))

    result1 = await task1
    result2 = await task2
    print(result1)
    print(result2)

asyncio.run(main_tasks())

# asyncio.Queue: プロデューサー・コンシューマーパターン
async def producer(q, items):
    for item in items:
        await q.put(item)
        await asyncio.sleep(0.5)
    await q.put(None)   # 終了シグナル

async def consumer(q):
    while True:
        item = await q.get()
        if item is None:
            break
        print(f"処理中: {item}")
        q.task_done()

async def main_queue():
    q = asyncio.Queue()
    await asyncio.gather(
        producer(q, [1, 2, 3, 4, 5]),
        consumer(q),
    )

asyncio.run(main_queue())
概要

asyncioはシングルスレッドで動作するイベントループを使って、複数のコルーチンを切り替えながら並行実行します。『await』に到達するとイベントループが別のコルーチンに制御を渡すため、I/O待ち時間を有効活用できます。

『asyncio.gather()』は全コルーチンを並行実行して、すべての結果をリストで返します。いずれかのコルーチンで例外が発生した場合はその例外を送出します。例外を無視したい場合はreturn_exceptions=Trueを指定します。

asyncioはI/O待ちには強力ですが、CPU密集処理はイベントループをブロックするため効果がありません。CPU密集処理と組み合わせたい場合はasyncio.to_thread()(Python 3.9+)を使ってスレッドに処理を委譲します。また、httpxやaiohttpなど非同期対応のHTTPクライアントライブラリと組み合わせて使うことが多いです。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。