Python: 同時プログラミング (12)

序文

この記事では、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_lotcar_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_filescoroutine task を使用して、それにファイルのリストを渡します。最後に、結合されたコンテンツの結果を出力します。

上記のコードを実行すると、複数のファイルの内容を同時に読み取り、結果として得られる 1 つの文字列に結合できます。これにより、ファイルの読み込み処理が効率化され、プログラムの実行速度が向上する。

2. asyncio モジュールの主な機能

1. 使い方asyncawaitキーワード

コルーチン関数を定義するときは、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関数は、イベント ループでのスケジュールと管理のためのオブジェクトとしてコルーチンをラップできます。

Guess you like

Origin blog.csdn.net/weixin_43431593/article/details/131257749