小白でも理解できる Python コルーチンと asyncio ガイド#
一、生活シーンから非同期プログラミングを理解する#
1.1 ミルクティーを買う 2 つの方法#
あなたが 3 杯のミルクティーを買うと仮定します。各杯の製作には 2 分かかります:
従来の方法(同期):
def ミルクティーを買う_同期():
for _ in range(3):
2分待つ() # じっと待つ
ミルクティーを受け取る()
# 総時間:3×2=6分 ❌
賢い方法(非同期):
async def ミルクティーを買う_非同期():
注文リスト = [注文(), 注文(), 注文()] # 同時に注文
await asyncio.gather(*注文リスト) # 待ちながらスマホをいじる
# 総時間:2分 ✅
1.2 コルーチンは配達員のようなもの#
配達員が同時に複数の注文を処理している様子を想像してください:
- A 店で料理を受け取る(待っている間に B 店へ)
- 途中で新しい注文を受ける(ルートを柔軟に調整)
- 配達後すぐに次の注文を受ける(時間を無駄にしない)
これがコルーチンの働き方です!複数の配達員(スレッド)は必要なく、1 人で効率的にタスクを完了できます。
二、最も簡単なコルーチン入門(実行可能なコード付き)#
2.1 こんにちはコルーチン版#
import asyncio
async def 挨拶(name): # 重要1:asyncでコルーチンを定義
print(f"{name}が作業を始めます")
await asyncio.sleep(1) # 重要2:待機時に中断
print(f"{name}の作業が完了しました")
async def 主タスク():
await asyncio.gather(
挨拶("小明"),
挨拶("小紅")
)
asyncio.run(主タスク()) # 重要3:イベントループを起動
出力結果:
小明が作業を始めます
小紅が作業を始めます
(1秒待機)
小明の作業が完了しました
小紅の作業が完了しました
2.2 実行プロセスの図解#
三、必ず押さえておくべき 3 つのコア概念#
3.1 コルーチンの三要素#
要素 | 説明 | 類比 |
---|---|---|
async def | コルーチン関数を宣言 | 配達注文に "急ぎ" ラベルを貼る |
await | 一時停止して制御権を譲る | 配達員が他の注文を配達するために一時的に離れる |
イベントループ | すべてのタスクのスケジューラー | 配達プラットフォームの配達システム |
3.2 よくある誤解リスト#
-
誤り:通常の関数内で await を使用
def 通常の関数(): await asyncio.sleep(1) # エラー!
-
誤り:タスクを作成するのを忘れる
async def 誤った例(): # 順次実行、並行性なし! await タスク1() await タスク2()
-
正しい方法:
async def 正しい例(): task1 = asyncio.create_task(タスク1()) task2 = asyncio.create_task(タスク2()) await task1 await task2
四、手取り足取り実践:複数の画像をダウンロード#
4.1 同期バージョン(亀のような速度)#
import requests
def 画像をダウンロード(url):
print(f"{url}のダウンロードを開始します")
data = requests.get(url).content
with open("画像.jpg", "wb") as f:
f.write(data)
print(f"{url}のダウンロードが完了しました")
def 主関数():
urls = ["url1", "url2", "url3"] # 3つの画像アドレスを仮定
for url in urls:
画像をダウンロード(url)
# 総時間:1枚あたりの時間 × 数量
4.2 非同期バージョン(飛ぶような感覚)#
import aiohttp
async def 非同期ダウンロード(url):
async with aiohttp.ClientSession() as session:
print(f"{url}のダウンロードを開始します")
async with session.get(url) as response:
data = await response.read()
with open(f"{url.split('/')[-1]}", "wb") as f:
f.write(data)
print(f"{url}のダウンロードが完了しました")
async def 主タスク():
urls = ["url1", "url2", "url3"]
await asyncio.gather(*[非同期ダウンロード(url) for url in urls])
asyncio.run(主タスク())
4.3 パフォーマンス比較#
画像数 | 同期時間 | 非同期時間 | 速度向上 |
---|---|---|---|
10 | 20 秒 | 2 秒 | 10 倍 |
100 | 200 秒 | 5 秒 | 40 倍 |
五、よくある質問と回答#
Q1:コルーチンとマルチスレッドの違いは?#
特性 | コルーチン | マルチスレッド |
---|---|---|
リソース使用 | 1 つのスレッドで全てを処理 | 各スレッドが独立したリソースを必要 |
切り替え方法 | 自発的に制御権を譲る | システムによって強制的に切り替え |
適用シーン | 大量の IO 操作に適して | 計算集約型タスクに適して |
プログラミングの難易度 | 非同期構文を理解する必要がある | スレッドセーフの問題を扱う必要がある |
Q2:いつコルーチンを使えないか?#
- 大量の CPU 計算が必要なシーン(例:動画のエンコード)
- 非同期をサポートしていないライブラリを使用する場合(例えば、従来のデータベースドライバ)
- 複数のコアで並列計算が必要な場合(マルチプロセスと組み合わせる必要がある)
Q3:コルーチンプログラムをデバッグするには?#
-
asyncio.run()
をエントリーポイントとして使用 -
コルーチン内で通常の print 文を使用
-
専門のデバッガを使用:
import logging logging.basicConfig(level=logging.DEBUG)
六、最適な学習ルートの提案#
6.1 初心者の 3 ステップ#
- まず同期コードを書いてビジネスプロセスを理解する
- 時間のかかる操作を async/await に置き換える
asyncio.gather
を使って並行性を実現する
6.2 おすすめの練習プロジェクト#
プロジェクトタイプ | 実現機能 | スキルポイント |
---|---|---|
天気クエリ | 複数の都市の天気を同時にクエリ | 基本的な非同期リクエスト |
ウェブ監視 | 複数のウェブサイトの状態を定期的にチェック | 非同期定期タスク |
チャットボット | 複数のユーザーのメッセージを同時に処理 | 並行メッセージ処理 |
七、この 5 つの文を覚えておけば大丈夫#
- async def:コルーチンのスタートライン
- await:IO に遭遇したら手を挙げて一時停止
- イベントループ:裏方の総スケジューラー
- create_task:コルーチンを実行可能なタスクに変える
- asyncio.run():プログラムの起動スイッチ
この記事は Mix Space によって xLog に同期更新されました
元のリンクは https://blog.kanes.top/posts/default/asyncio