Pythonの非同期処理を学ぼう!asyncとawaitの使い方解説

PRについて
※このサイトはアフィリエイト広告(Amazonアソシエイト含む)を掲載しています。
スポンサーリンク
※このサイトはアフィリエイト広告(Amazonアソシエイト含む)を掲載しています。
Pythonの非同期処理を学ぼう!asyncとawaitの使い方解説 Tips集
Pythonプログラミング逆引き大全

今回は非同期処理をPythonで実現する方法について学んでいきます。

Pythonのasyncawaitを使うことで、複雑な非同期処理を簡単に記述でき、特にI/O処理が絡むプログラムでは大きなパフォーマンス向上が期待できます。

ごまこ
ごまこ

非同期処理ってどういうものなんでしょう?
基礎的な話から教えてもらえるとありがたいです!

ごまお
ごまお

「非同期処理」は、処理を待っている間に他の作業を行う処理技術です!
まずは非同期処理ついて学んだ上で、実際のプログラムや使用例を見ていきましょう!

はじめに

非同期処理とは何か?

プログラミングにおける「非同期処理」とは、ある処理を待っている間に他の作業を同時に行う技術です。

たとえば、インターネットからデータをダウンロードするような場合、ダウンロードが完了するまで何もしないのではなく、その間に他の作業を進められるようにする仕組みが非同期処理です。

Pythonでは、バージョン3.5以降、非同期処理をより簡単に扱うために、asyncawaitというキーワードが導入されました。

これらを使うことで、複雑な非同期処理をシンプルに記述できるようになっています。

Pythonで非同期処理を扱う場面

非同期処理は、特に次のような場面で活躍します。

  • Webスクレイピング:複数のウェブページに同時にリクエストを送り、データを取得する。
  • ネットワーク通信:チャットアプリやオンラインゲームのように、サーバーとリアルタイムでデータをやり取りする。
  • I/O処理:ファイルの読み書きや、データベースからのデータ取得など、時間がかかる入出力操作を効率的に処理する。

asyncとawaitの基本的な役割

Pythonで非同期処理を行うためには、まず関数をasyncで定義し、その関数内で非同期処理が行われる部分にawaitを付けるという形が基本です。

  • async:非同期関数を定義するために使用します。
  • await:非同期処理が終わるまで待つために使います。

次の章では、同期処理と非同期処理の違いについて、簡単な例を交えながら説明します。

同期処理と非同期処理の違い

同期処理とは

同期処理は、1つのタスクが完了するまで次のタスクが開始されない形式の処理です。

これにより、1つのタスクが完了するまで他の作業は中断されます。

たとえば、データベースに問い合わせを送った後、その結果が返ってくるまでプログラム全体が待つというイメージです。

非同期処理のメリット

一方、非同期処理は「待たない」処理です。

あるタスクが進行している間に、別のタスクを同時に進めることができます。

これにより、時間のかかる操作を効率化し、プログラム全体のパフォーマンスを向上させることが可能です。

簡単な例:同期 vs 非同期

以下は、同期処理と非同期処理の違いをシンプルに説明する例です。

同期処理の例

import time

def task():
    print("Task started")
    time.sleep(2)  # 2秒待機
    print("Task finished")

task()
print("Next task started")

このプログラムでは、task関数が実行されると2秒間プログラムが停止し、その後に「Next task started」が表示されます。

これが同期処理です。

非同期処理の例

import asyncio

async def task():
    print("Task started")
    await asyncio.sleep(2)  # 2秒待機
    print("Task finished")

async def main():
    await task()
    print("Next task started")

asyncio.run(main())

非同期処理では、awaitを使って2秒間の待機が発生している間に、他の処理も並行して実行できる準備が整います。

awaitを使うことで、プログラム全体が止まるのではなく、他の処理が行われます。

asyncとawaitの基本的な使い方

async defで非同期関数を定義

Pythonで非同期関数を定義するには、async defという形で関数を作ります。

これによって、その関数は非同期に実行されることが期待されます。

async def example():
    print("This is an async function")

この関数は非同期ですが、単独で呼び出しても何も特別なことは起こりません。

非同期関数を呼び出すときは、awaitまたは非同期ランタイムを使用して実行する必要があります。

awaitで他の非同期処理を待つ

非同期関数の中で、他の非同期処理の完了を待つ場合には、awaitを使います。

例えば、次のコードは2秒間待機してから次の処理を行います。

import asyncio

async def example():
    print("Waiting for 2 seconds...")
    await asyncio.sleep(2)
    print("Done waiting!")

awaitは、非同期関数内で時間のかかる処理が完了するのを「一時停止して待つ」ためのキーワードです。

非同期処理の例:時間を待つ処理 (asyncio.sleep)

非同期処理では、例えばasyncio.sleep()を使って時間待機を行います。

この場合、他の処理がブロックされず、並列で処理が進むため、効率よく複数のタスクを処理することが可能です。

非同期タスクを同時に実行する

asyncio.gatherで複数の非同期処理を同時実行

複数の非同期処理を同時に実行するには、asyncio.gather()を使用します。

これは、複数のタスクを並行して実行するのに便利な関数です。以下に実例を示します。

import asyncio

async def task_1():
    print("Task 1 started")
    await asyncio.sleep(2)
    print("Task 1 finished")

async def task_2():
    print("Task 2 started")
    await asyncio.sleep(1)
    print("Task 2 finished")

async def main():
    await asyncio.gather(task_1(), task_2())

asyncio.run(main())

この例では、task_1task_2が同時に実行され、それぞれの処理が終了したら次の行が実行されます。

task_1は2秒待機し、task_2は1秒待機するため、1秒後にはtask_2が完了し、続けてtask_1が完了するという流れになります。

実例:複数のWebリクエストを並列で行う

以下は、複数のWebリクエストを非同期に送る例です。

import asyncio
import aiohttp

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

async def main():
    async with aiohttp.ClientSession() as session:
        urls = ["https://example.com", "https://python.org", "https://openai.com"]
        tasks = [fetch(session, url) for url in urls]
        responses = await asyncio.gather(*tasks)
        for response in responses:
            print(response[:100])  # 最初の100文字だけ表示

asyncio.run(main())

aiohttpというライブラリを使って、複数のURLから非同期でデータを取得しています。

これにより、ネットワーク待ち時間を無駄にせず効率的にWebリクエストを並列処理できます。

エラーハンドリングと非同期処理

非同期処理中の例外処理

非同期処理中に例外が発生した場合も、通常のPythonと同様にtry/exceptブロックを使ってエラーハンドリングが可能です。

import asyncio

async def faulty_task():
    print("Task started")
    await asyncio.sleep(1)
    raise ValueError("Something went wrong!")

async def main():
    try:
        await faulty_task()
    except ValueError as e:
        print(f"Error: {e}")

asyncio.run(main())

try/exceptを使ったエラーハンドリング

この例では、faulty_taskで1秒待った後にValueErrorを発生させますが、main関数内でtryブロックを使うことで、そのエラーをキャッチし、適切に処理しています。

まとめ

Pythonのasyncawaitを使うことで、複雑な非同期処理を簡単に記述でき、特にI/O処理が絡むプログラムでは大きなパフォーマンス向上が期待できます。

非同期処理を使う際には、複数のタスクを同時に実行するためのasyncio.gatherや、エラーを適切に処理するためのtry/exceptといった技法も組み合わせると効果的です。

非同期処理は一度に全てを理解するのは難しいかもしれませんが、実際のプロジェクトやタスクで少しずつ使いこなすことで、その便利さと強力さを実感できるはずです。

興味がある方は、より高度な非同期プログラミングに挑戦してみてください!

このサイトのトップページへは以下へアクセス!

Python自動処理の教科書
Tips集
ゴマフリーダムをフォローする

コメント

達人に学ぶDB設計 徹底指南書

最短コースでわかる ディープラーニングの数学

あたらしい機械学習の教科書 第3版

ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装

タイトルとURLをコピーしました