Python での非同期プログラミング

Mar 06 2023
非同期プログラミングは、あるプロセスの終了を待ってから次のプロセスに進むことなく、多くのプロセスを同時に独立して実行できるようにするプログラミング パラダイムです。このブログ投稿では、非同期プログラミングとは何か、またそれを Python で使用する方法について説明します。
Python での非同期プログラミング

非同期プログラミングは、あるプロセスの終了を待ってから次のプロセスに進むことなく、多くのプロセスを同時に独立して実行できるようにするプログラミング パラダイムです。このブログ投稿では、非同期プログラミングとは何か、またそれを Python で使用する方法について説明します。

非同期プログラミングとは何ですか?

同期プログラミングでは、コンピューターは命令を順番に実行し、ジョブが完了するまで実行をブロックしてから次のジョブに進みます。
一方、非同期プログラミングでは、プログラムは 1 つの操作を開始し、元のタスクが完了するまで実行を停止することなく別の操作に進むことができます。

非同期プログラミングは、ネットワーク I/O やデータベース操作などのプロセスが完了するまでに長い時間がかかる可能性がある状況で特に有益です。非同期プログラミングは、遅い操作が完了するのを待っている間にプログラムが他のアクティビティを続行できるようにすることで、ソフトウェア アプリケーションのパフォーマンスと応答性を向上させるのに役立ちます。

使用するプログラミング言語とフレームワークに応じて、コールバック、プロミス、または async/await キーワードなどのさまざまな戦略を使用して非同期プログラミングを実行できます。

非同期プログラミングと多重処理の違い

非同期プログラミングとマルチプロセッシングの主な違いは、非同期プログラミングでは単一スレッド内でノンブロッキング操作を実行できるのに対し、マルチプロセッシングでは多くのコアまたはプロセスを使用して作業を同時に完了することです。

非同期プログラミングとスレッド化の違い

非同期プログラミングとスレッド化の主な違いは、非同期プログラミングでは単一のスレッドを使用してノンブロッキング操作が可能であるのに対し、スレッド化では複数のスレッドを使用して複数のタスクを並行して実行できることです。

違いの詳細:トレッド、マルチプロセッシング、非同期プログラミング

Asyncioの使い方は?

まず、一度にジョブを開始して終了する簡単なプログラムを作成しましょう。

import time
import asyncio

def do_job(s):
    print(f"{s} started")
    await asyncio.sleep(1)
    print(f"{s} done")

def main():
    start = time.perf_counter()
    todo = ["Job A", "Job B", "Job C"]
    for job in todo:
        do_job(job)
    
    end = time.perf_counter()
    print(f"Took: {end-start:.3f} seconds")

main()

# OUTPUT
# Job A started
# Job Adone
# Job B started
# Job B done
# Job C started
# Job C done
# Took: 3.009 seconds

コルーチンの作成と実行

コルーチンは、実行中のさまざまな時点で中断および再開できる関数の一種です。言い換えれば、コルーチンを使用すると、中断して別のことを実行し、中断したところから再開できるコードを作成できます。

コルーチンを作成するには、キーワードasyncの前にキーワードを使用する必要がありますdef。コルーチンを呼び出しても、実行したい関数は呼び出されません。タスクが作成されます。

import time
import asyncio

async def do_job(s):
  ...

async def main():
  ...

main()

asyncio.run(main())

このコードを実行すると、おそらく次のようなエラーが発生します。

RuntimeWarning: coroutine '...' was never awaited

import time
import asyncio

async def do_job(s):
    print(f"{s} started")
    await asyncio.sleep(1)
    print(f"{s} done")

async def main():
    start = time.perf_counter()
    todo = ["Job A", "Job B", "Job C"]
    for job in todo:
        await do_job(job)
    
    end = time.perf_counter()
    print(f"Took: {end-start:.3f} seconds")

asyncio.run(main())

# OUTPUT
# Job A started
# Job A done
# Job B started
# Job B done
# Job C started
# Job C done
# Took: 3.009 seconds

await asyncio.sleep(1)

tasks = [asyncio.create_task(do_job(item)) for item in todo]
done, pending = await asyncio.wait(tasks)

import time
import asyncio

async def do_job(s):
    print(f"{s} started")
    await asyncio.sleep(1)
    print(f"{s} done")

async def main():
    start = time.perf_counter()
    todo = ["Job A", "Job B", "Job C"]
    
    tasks = [asyncio.create_task(do_job(item)) for item in todo]
    done, pending = await asyncio.wait(tasks)
    
    end = time.perf_counter()
    print(f"Took: {end-start:.3f} seconds")

asyncio.run(main())

# OUTPUT
# Job A started
# Job B started
# Job C started
# Job A done
# Job B done
# Job C done
# Took: 1.009 seconds

Python での非同期プログラミングについて詳しくは、ビデオをご覧ください。(非同期 Python の紹介 | Web クローラーの作成)