序文
この記事では、Python のマルチコルーチン同時プログラミング(パート 2)について説明します。同時実行性を実現するために組み込みの基本ライブラリ asyncio を使用します。まず、このモジュールを公式経由で簡単に使用します。最初にしっかりとした基礎を築き、基本的な使い方と認識を身につけてください。これについては、後続の記事で詳しく説明します。
この記事は Python 同時プログラミングの 12 回目の記事です 前回の記事のアドレスは以下のとおりです。
Python: 同時プログラミング (11)_ライオン キングのブログ - CSDN ブログ
次回記事のアドレスは以下の通りです。
Python: 同時プログラミング (13)_ライオン キングのブログ-CSDN ブログ
1.実戦
1. リアルタイム チャット システムをシミュレートします。各コルーチンはユーザーを表し、ユーザーはメッセージを送受信できます。すべてのメッセージがコンソールに出力されます
import asyncio
# 定义聊天用户类
class ChatUser:
def __init__(self, name):
self.name = name
async def send_message(self, message):
print(f"{self.name}: Sending message: {message}")
await asyncio.sleep(1) # 模拟发送消息的延迟
async def receive_message(self, message):
print(f"{self.name}: Received message: {message}")
await asyncio.sleep(1) # 模拟接收消息的延迟
# 定义聊天任务
async def chat_task(user):
while True:
message = input(f"{user.name}: Enter message (or 'quit' to exit): ")
if message == "quit":
break
await user.send_message(message)
await user.receive_message(message)
# 创建聊天用户
user1 = ChatUser("User1")
user2 = ChatUser("User2")
# 创建事件循环
loop = asyncio.get_event_loop()
# 运行聊天任务
tasks = [
asyncio.ensure_future(chat_task(user1)),
asyncio.ensure_future(chat_task(user2))
]
loop.run_until_complete(asyncio.wait(tasks))
# 关闭事件循环
loop.close()
上記のコードでは、2 つのチャット ユーザー オブジェクトを作成しuser1
、関数user2
を使用してchat_task
チャット タスクを定義しました。各チャット タスクは、コルーチンを介してメッセージを送受信するユーザーの機能を実装します。メイン ループでは 2 つのチャット タスクを実行し、asyncio.wait()
すべてのタスクが完了するまで待機します。最後に、イベント ループを閉じます。
上記のコードを実行すると、各ユーザーはコンソールにメッセージを入力して相手にメッセージを送信すると同時に、相手が送信したメッセージを受信してコンソールにメッセージを出力することができます。これは、単純なリアルタイム チャット システムをシミュレートします。
2. 複数の車両が同時に駐車場に進入し、駐車スペースを奪い合うことをシミュレートします。各コルーチンは車両を表し、駐車場に入った後ランダムな時間待機してから駐車場から出ます。
import asyncio
import random
# 定义停车场类
class ParkingLot:
def __init__(self, capacity):
self.capacity = capacity
self.available_spots = capacity
async def enter(self, car):
print(f"Car {car} entering the parking lot.")
if self.available_spots == 0:
print(f"Car {car} is waiting for a spot.")
await asyncio.sleep(1) # 模拟等待时间
await self.enter(car) # 递归调用,继续尝试进入停车场
else:
self.available_spots -= 1
print(f"Car {car} parked. Available spots: {self.available_spots}")
async def exit(self, car):
await asyncio.sleep(random.randint(1, 5)) # 模拟停留时间
self.available_spots += 1
print(f"Car {car} left the parking lot. Available spots: {self.available_spots}")
# 定义车辆任务
async def car_task(car, parking_lot):
await parking_lot.enter(car)
await parking_lot.exit(car)
# 创建停车场对象
parking_lot = ParkingLot(capacity=5)
# 创建事件循环
loop = asyncio.get_event_loop()
# 创建车辆任务
tasks = [
asyncio.ensure_future(car_task(car, parking_lot)) for car in range(10)
]
loop.run_until_complete(asyncio.wait(tasks))
# 关闭事件循环
loop.close()
上記のコードでは、駐車場オブジェクトを作成しparking_lot
、car_task
関数を使用して車両タスクを定義しました。各車両はコルーチンを通じて駐車場への入出庫の機能を実現します。メインループでは、10 個の車両タスクを作成し、次のコマンドを使用してasyncio.wait()
すべてのタスクが完了するのを待ちます。各車両が駐車場に進入する際、駐車場に空き駐車スペースがない場合には、無事に駐車場に進入できるまで一定時間待機した後、再度駐車場への進入を試みる。各車両の滞在時間はランダムであり、駐車場に滞在する車両の状況をシミュレートします。
上記のコードを実行すると、複数の車両が同時に駐車場に入場して駐車スペースを奪い合い、一定時間待機してから駐車場から退場し、関連情報を同時に印刷することができます。これは、複数の車両が同時に駐車場に進入するシナリオをシミュレートします。
3. 複数のファイルの内容を同時に読み取り、読み取った内容を結果文字列にマージします。
import asyncio
async def read_file(file_name):
print(f"Reading file: {file_name}")
content = ""
try:
with open(file_name, 'r', encoding="utf-8", errors='ignore') as file:
content = file.read()
except FileNotFoundError:
print(f"File not found: {file_name}")
return content
async def read_files(file_names):
tasks = [read_file(file_name) for file_name in file_names]
results = await asyncio.gather(*tasks)
return "".join(results)
# 要读取的文件列表
files = ["file1.txt", "file2.txt", "file3.txt"]
# 创建事件循环
loop = asyncio.get_event_loop()
# 执行并发读取文件任务
result = loop.run_until_complete(read_files(files))
print("Merged content:", result)
# 关闭事件循环
loop.close()
上記のコードでは、read_file
単一のファイルのコンテンツを読み取り、そのコンテンツをコルーチンとして返す関数を定義しました。次に、read_files
ファイル名のリストを取得し、複数のread_file
コルーチン タスクを作成し、asyncio.gather
を使用してすべてのタスクが完了するのを待機し、結果を文字列にマージする関数を定義します。
メイン ループでは、イベント ループ オブジェクトを作成し、run_until_complete
メソッド run read_files
coroutine task を使用して、それにファイルのリストを渡します。最後に、結合されたコンテンツの結果を出力します。
上記のコードを実行すると、複数のファイルの内容を同時に読み取り、結果として得られる 1 つの文字列に結合できます。これにより、ファイルの読み込み処理が効率化され、プログラムの実行速度が向上する。
2. asyncio モジュールの主な機能
1. 使い方async
とawait
キーワード
コルーチン関数を定義するときは、async
キーワードを使用して関数をコルーチン関数としてマークし、await
コルーチン内でキーワードを使用して非同期操作の完了を待ちます。
2.asyncio.run()
メインのコルーチンを実行するために使用します
関数を使用しasyncio.run()
てメイン コルーチンを実行し、イベント ループを自動的に作成して閉じることができるため、コード構造が簡素化されます。
3.asyncio.gather()
複数のコルーチン タスクの同時待機を使用する
asyncio.gather()
関数は複数のコルーチン タスクを引数として受け取り、それらがすべて完了するまで待つことができます。これにより、複数のタスクを同時に実行できます。
4.asyncio.wait()
反復可能オブジェクト内のコルーチン タスクを処理するために使用します。
asyncio.wait()
関数は、反復可能なオブジェクト (リストやコレクションなど) でコルーチン タスクを受け取り、それらのいずれかが完了するまで待機します。return_when
待機条件はasyncio.FIRST_COMPLETED
、 、asyncio.ALL_COMPLETED
などのパラメータで指定できます。
5.asyncio.sleep()
一時停止時間を作成するために使用します
asyncio.sleep()
関数はコルーチンに一時停止時間を作成し、イベント ループを指定した時間一時停止して、他のコルーチンが実行できるようにすることができます。
6.asyncio.TimeoutError
タイムアウトを処理するために使用します
関数を使用してasyncio.wait_for()
コルーチン タスクのタイムアウト期間を設定し、asyncio.TimeoutError
例外をキャッチしてタイムアウト状況を処理できます。
7.asyncio.Lock()
ミューテックスの実装に使用します
asyncio.Lock()
このクラスは相互排他ロック メカニズムを提供し、コルーチン内でステートメントを使用してasync with
ロックを取得および解放し、同時に 1 つのコルーチンだけが共有リソースにアクセスできるようにすることができます。
8.asyncio.Queue()
コルーチン間のメッセージ受け渡しを実装するために使用します。
asyncio.Queue()
クラスは、コルーチン間のメッセージング チャネルとして使用できます。コルーチンはメッセージをキューに入れ、別のコルーチンはキューからメッセージを取得することができ、コルーチン間の非同期通信を実現します。
9.asyncio.run_coroutine_threadsafe()
マルチスレッドでコルーチンをスケジュールするために使用します
asyncio.run_coroutine_threadsafe()
関数は、マルチスレッド環境でコルーチン タスクをスケジュールし、実行のためにイベント ループに送信できます。
10.asyncio.ensure_future()
コルーチンのラップに使用します
asyncio.ensure_future()
Task
関数は、イベント ループでのスケジュールと管理のためのオブジェクトとしてコルーチンをラップできます。