PYTHON MEBY

Pythonで非同期関数を定義する(async def, Python 3.5以降)

この記事では、Python 3.5以降で導入された非同期関数`async def`の使い方を解説します。非同期処理の基本的な概念、`async`と`await`キーワードの使い方、そして具体的な使用例を示します。

目次

非同期関数とは?

非同期関数とは、IOバウンドな処理(ネットワーク通信、ファイル読み込みなど)を並行的に実行することで、プログラム全体の処理時間を短縮するための関数です。`async def`キーワードを使って定義します。

従来の同期処理では、処理が完了するまで次の処理に進めませんが、非同期処理では、処理を開始したら次の処理に進み、処理が完了したら結果を取得します。そのため、複数のIOバウンドな処理を同時に実行できるため効率的です。

async defキーワード

`async def`キーワードを使って非同期関数を定義します。通常の関数定義`def`と似ていますが、`async`キーワードが付いている点が異なります。

import asyncio

async def my_async_function():
    print('非同期関数の中です')
    await asyncio.sleep(1)  # 1秒待つ
    print('非同期関数が完了しました')

この例では、`asyncio.sleep(1)`で1秒間処理を一時停止します。この間、他の非同期処理を実行できます。

awaitキーワード

`await`キーワードは、非同期関数の呼び出しに使用します。`await`の後に続く非同期関数が完了するまで、処理を一時停止します。

async def main():
    await my_async_function()

asyncio.run(main())

非同期関数の呼び出し

非同期関数は、`asyncio.run()`関数を使って呼び出します。`asyncio.run()`関数は、イベントループを開始し、非同期関数を処理します。

import asyncio

async def my_async_function():
    # ...

async def main():
    await my_async_function()

asyncio.run(main())

awaitと同期処理との違い

awaitを使うことで、非同期関数の中で同期的に処理を待つことができます。awaitがないと、非同期関数はすぐに次の処理に進みます。

import asyncio

async def async_func():
    print('async_func開始')
    await asyncio.sleep(2)
    print('async_func終了')

async def main():
    print('main開始')
    await async_func()
    print('main終了')

asyncio.run(main())

# 出力結果:
# main開始
# async_func開始
# async_func終了
# main終了

この例では、`await async_func()`によって`main`関数は`async_func`関数が完了するまで待ちます。もし`await`がないと、`main`関数は`async_func`関数が完了する前に`main終了`を出力します。

エラー処理

非同期関数内でのエラー処理は、`try...except`ブロックで行います。

import asyncio

async def my_async_function():
    try:
        # エラーが発生する可能性のある処理
        result = await some_async_operation()
    except Exception as e:
        print(f'エラーが発生しました: {e}')
        return None
    return result

実践例:非同期で複数のWebサイトにアクセスする

複数のWebサイトに同時にアクセスしてHTMLを取得する例です。`aiohttp`ライブラリを使用します。

import asyncio
import aiohttp

async def fetch_html(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    async with aiohttp.ClientSession() as session:
        tasks = [
            fetch_html(session, 'https://www.example.com'),
            fetch_html(session, 'https://www.google.com'),
        ]
        results = await asyncio.gather(*tasks)
        for result in results:
            print(result[:100])  # 先頭100文字だけ表示

asyncio.run(main())

関連記事