python:并发编程(十二)

前言

本文将和大家一起探讨python的多协程并发编程(下篇),使用内置基本库asyncio来实现并发,先通过官方来简单使用这个模块。先打好基础,能够有个基本的用法与认知,后续文章,我们再进行详细使用。

本文为python并发编程的第十二篇,上一篇文章地址如下:

python:并发编程(十一)_Lion King的博客-CSDN博客

下一篇文章地址如下:

python:并发编程(十三)_Lion King的博客-CSDN博客

一、实战

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()

在上述代码中,我们创建了两个聊天用户对象user1user2,并使用chat_task函数定义了聊天任务。每个聊天任务通过协程实现用户的发送和接收消息的功能。在主循环中,我们运行了两个聊天任务,并使用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方法运行read_files协程任务,并将文件列表传递给它。最后,我们打印合并后的内容结果。

通过运行以上代码,可以并发地读取多个文件的内容,并将内容合并到一个结果字符串中。这样可以更高效地处理文件读取操作,提高程序的执行速度。

二、asyncio模块主要功能

1、使用asyncawait关键字

在定义协程函数时,使用async关键字标记函数为协程函数,然后在协程内部使用await关键字来等待异步操作的完成。

2、使用asyncio.run()来运行主协程

可以使用asyncio.run()函数来运行主协程,并自动创建和关闭事件循环,简化代码结构。

3、使用asyncio.gather()同时等待多个协程任务

asyncio.gather()函数可以接收多个协程任务作为参数,并等待它们全部完成。这样可以实现并发执行多个任务。

4、使用asyncio.wait()来处理可迭代对象中的协程任务

asyncio.wait()函数接收一个可迭代对象(如列表或集合)中的协程任务,并等待它们中的任何一个完成。可以使用return_when参数指定等待条件,如asyncio.FIRST_COMPLETEDasyncio.ALL_COMPLETED等。

5、使用asyncio.sleep()来创建暂停时间

asyncio.sleep()函数可以在协程中创建一个暂停时间,让事件循环暂停一段指定的时间,以便其他协程有机会执行。

6、使用asyncio.TimeoutError来处理超时

可以使用asyncio.wait_for()函数来设置协程任务的超时时间,并捕获asyncio.TimeoutError异常来处理超时情况。

7、使用asyncio.Lock()实现互斥锁

asyncio.Lock()类提供了互斥锁的机制,可以在协程中使用async with语句来获取和释放锁,确保同一时间只有一个协程可以访问共享资源。

8、使用asyncio.Queue()实现协程间的消息传递

asyncio.Queue()类可以用作协程之间的消息传递通道。一个协程可以将消息放入队列,而另一个协程可以从队列中获取消息,实现协程间的异步通信。

9、使用asyncio.run_coroutine_threadsafe()在多线程中调度协程

asyncio.run_coroutine_threadsafe()函数可以在多线程环境中调度协程任务,并将其提交给事件循环进行执行。

10、使用asyncio.ensure_future()来包装协程

asyncio.ensure_future()函数可以将协程包装为Task对象,以便在事件循环中进行调度和管理。

猜你喜欢

转载自blog.csdn.net/weixin_43431593/article/details/131257749