小白的Python并发编程

基础语法糖

语法糖功能对应底层机制
async def定义协程函数创建 Coroutine 对象
await挂起并等待协程完成调用 __await__() 方法
async for异步迭代使用 __aiter__()__anext__()
async with异步上下文管理使用 __aenter__()__aexit__()
  1. async def —— 协程函数定义
# 示例
import asyncio

async def hello():
    await asyncio.sleep(1)
    return "Hello"

# 调用返回协程对象,不立即执行
coro = hello()  
print(type(coro))  # <class 'coroutine'>

# 需要 await 或 asyncio.run() 来执行
result = asyncio.run(hello())
# 使用语法糖
async def fetch_data():
    return await some_async_operation()

# 等价于(底层实现)
def fetch_data():
    async def _coro():
        return await some_async_operation()
    return _coro()

作用:

  • 将普通函数转换为协程函数

  • 调用时返回 Coroutine 对象,而非直接执行

  • 允许在函数内部使用 await

  1. await —— 协程等待
# 示例
async def main():
    # await 语法糖:等待两个任务完成
    task1 = asyncio.create_task(fetch_user())
    task2 = asyncio.create_task(fetch_posts())
    
    user = await task1  # 语法糖:等待任务1
    posts = await task2  # 语法糖:等待任务2
    
    return user, posts
# 使用语法糖
result = await coroutine_obj

# 等价于(简化版底层)
result = yield from coroutine_obj.__await__()

# await 的对象必须是 awaitable,如:
# 协程对象 (coroutine)
# 任务 (Task)
# 具有 __await__() 方法的对象

作用:

  • 挂起当前协程,让出控制权给事件循环

  • 等待目标协程完成后恢复执行

  • 只能在 async def 函数中使用

  1. async for —— 异步迭代器
# 示例1_异步计数器
class AsyncCounter:
    def __init__(self, max_count):
        self.max_count = max_count
        self.current = 0
    
    def __aiter__(self):
        return self  # 返回自身作为迭代器
    
    async def __anext__(self):
        if self.current >= self.max_count:
            raise StopAsyncIteration  # 迭代结束信号
        
        # 模拟异步操作(如网络延迟)
        await asyncio.sleep(0.1)
        value = self.current
        self.current += 1
        return value

# 使用
async def main():
    async for num in AsyncCounter(3):
        print(f"Count: {num}")

# 输出:
# Count: 0
# Count: 1  
# Count: 2
# 示例2_异步数据库查询
class AsyncDatabaseCursor:
    def __init__(self, query):
        self.query = query
        self.index = 0
        
    def __aiter__(self):
        return self
        
    async def __anext__(self):
        if self.index >= 3:  # 模拟3条记录
            raise StopAsyncIteration
        # 模拟异步数据库查询
        await asyncio.sleep(0.1)
        result = f"Record {self.index}"
        self.index += 1
        return result

async def main():
    # async for 语法糖
    async for record in AsyncDatabaseCursor("SELECT * FROM users"):
        print(record)
# 使用语法糖
async for item in async_iterable:
    process(item)

# 等价于(底层展开)
iter_obj = async_iterable.__aiter__()
while True:
    try:
        item = await iter_obj.__anext__()
        process(item)
    except StopAsyncIteration:
        break

作用:

  • 在每次迭代时自动 await下一个元素

  • 处理可能涉及 I/O 的迭代操作(如数据库游标、网络流)

  1. async with —— 异步上下文管理器
# 示例
class AsyncHTTPClient:
    def __init__(self, base_url):
        self.base_url = base_url
        self.session = None
    
    async def __aenter__(self):
        print(f"Creating session for {self.base_url}")
        # 模拟异步创建会话
        await asyncio.sleep(0.1)
        self.session = f"Session-{id(self)}"
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        print(f"Closing session {self.session}")
        # 模拟异步关闭会话
        await asyncio.sleep(0.1)
        self.session = None
        
        # 如果有异常,可以选择处理或传播
        if exc_type is not None:
            print(f"Exception occurred: {exc_val}")
            # 返回 None 或 False 会传播异常
            return False
    
    async def get(self, path):
        if not self.session:
            raise RuntimeError("Session not active")
        url = f"{self.base_url}{path}"
        print(f"GET {url} using {self.session}")
        await asyncio.sleep(0.2)  # 模拟网络请求
        return f"Response from {url}"

# 使用
async def fetch_data():
    async with AsyncHTTPClient("https://api.example.com") as client:
        response = await client.get("/users")
        print(response)
# 使用语法糖
async with resource as obj:
    do_something(obj)

# 等价于(底层展开)
manager = (resource)
aexit = type(manager).__aexit__
aenter_result = type(manager).__aenter__(manager)
try:
    obj = aenter_result
    do_something(obj)
except Exception as exc:
    if not await aexit(manager, type(exc), exc, exc.__traceback__):
        raise
else:
    await aexit(manager, None, None, None)

作用:

  • 异步获取和释放资源

  • 常用于需要异步初始化/清理的场景(如网络连接、文件操作)

Python并发编程的核心组成部分

1. 主循环

作用:负责任务调度、IO 事件监听、状态管理

# 主循环
主循环(while ture):
    检查所有任务列表中的所有任务 -> 获取可执行的任务列表 +  已完成的任务列表
    
	遍历就绪任务列表:
		执行已就绪的任务
       
	遍历已完成的任务列表:
		在任务列表中移除已完成的任务
       
    检查任务列表:
      如果任务列表中的任务都已完成,则终止循环

功能:

  1. 获取所有可执行的任务和已经完成的任务

  2. 执行已经就绪的任务

  3. 移除已经完成的任务

  4. 检查任务列表中的任务是否全部完成

注意点:

  • 主循环(事件循环)在单线程中运行,所有任务都在这个线程内切换执行。

  • 仅当任务遇到 await(表示需要等待 IO)时才会切换,纯计算任务不会触发切换。

2. 协程

协程是异步任务的基本单元,是一种用户态的上下文切换技术,其实就是通过一个线程实现代码块相互切换执行,本质是可暂停 / 恢复的函数。

  1. 调用协程不会立即执行,而是返回一个协程对象。
  2. 必须通过事件循环调度(如 awaitcreate_task)才能执行。
#示例
import asyncio

async def my_coroutine_1():
    print("协程1开始")
    await asyncio.sleep(2)
    print("协程1结束")
    return "结果1"

async def my_coroutine_2():
    print("协程2开始")
    await asyncio.sleep(1)
    print("协程2结束")
    return "结果2"

async def main():
    result1 = await task1
    result2 = await task2

asyncio.run(main())

协程的生命周期:

创建:coro = my_coroutine() → 未执行状态。
运行:await corocreate_task(coro) → 进入事件循环。
暂停: 执行到 await 语句 → 等待 IO 时挂起。
恢复:IO 完成 → 从暂停点继续执行。
完成: 执行到函数末尾 → 返回结果或抛出异常。

3. 任务

任务是协程的包装器,由事件循环直接调度,用于实现并发。任务会将协程注册到事件循环,并跟踪其状态(运行中 / 已完成 / 已取消)。

# 示例1
import asyncio

async def my_coroutine_1():
    print("协程1开始")
    await asyncio.sleep(2)
    print("协程1结束")
    return "结果1"

async def my_coroutine_2():
    print("协程2开始")
    await asyncio.sleep(1)
    print("协程2结束")
    return "结果2"

async def main():
    # 同时创建并启动两个任务(并发)
    task1 = asyncio.create_task(my_coroutine_1())  # 立即调度执行
    task2 = asyncio.create_task(my_coroutine_2())  # 立即调度执行
    
    print("两个协程已启动,正在并发运行...")
    
    # 等待它们完成(顺序 await 不影响执行顺序)
    result1 = await task1
    result2 = await task2
    
    print("最终结果:", result1, result2)

asyncio.run(main())
# 示例2
async def task_func(name, delay):
    print(f"任务 name={name}, delay={delay} === 111")
    await asyncio.sleep(delay)
    print(f"任务 name={name}, delay={delay} === 222")
    return f"任务 {name} 完成"
 
 
async def main():
    # 创建任务(立即加入事件循环,开始调度)
    task_list = [
        asyncio.create_task(task_func("A", 1), name="task_A"),
        asyncio.create_task(task_func("B", 2), name="task_B"),
    ]
 
    done, pending = await asyncio.wait(task_list, timeout=None)
 
    # 等待任务完成并获取结果
    print(done)
 
 
asyncio.run(main())
任务相关语法
  • task.done():判断任务是否完成。

  • task.result():获取任务返回值(任务未完成时调用会报错)。

  • task.cancel():取消任务(触发 CancelledError)。

  • task.add_done_callback(func):注册回调函数(任务完成后执行)。

# 示例1_task.done()+task.result()
import asyncio

async def my_coroutine_1():
    print("协程1开始")
    await asyncio.sleep(2)
    print("协程1结束")
    return "结果1"

async def my_coroutine_2():
    print("协程2开始")
    await asyncio.sleep(1)
    print("协程2结束")
    return "结果2"

async def main():
    # 同时创建并启动两个任务(并发)
    task1 = asyncio.create_task(my_coroutine_1())  # 立即调度执行
    task2 = asyncio.create_task(my_coroutine_2())  # 立即调度执行
    
    print("两个协程已启动,正在并发运行...")
    while(1):
        print("任务1:",task1.done())
        print("任务2:",task2.done())
        await asyncio.sleep(0.5)
        if task1.done() == True and  task1.done() == True:
            break;
    # 等待它们完成(顺序 await 不影响执行顺序)
    result1 = await task1
    result2 = await task2

    print(task1.result(),task2.result())

asyncio.run(main())
# 示例2_task.cancel()
import asyncio
async def cancellable_task():
    try:
        print("可取消任务开始")
        await asyncio.sleep(3)  # 这里会被中断
        print("可取消任务结束")
        return "正常完成"
    except asyncio.CancelledError:
        print("任务被取消!")
        raise  # 重新抛出以确保任务状态为 cancelled

async def cancel_demo():
    task = asyncio.create_task(cancellable_task())
    
    # 1秒后取消任务
    await asyncio.sleep(1)
    task.cancel()
    
    try:
        result = await task
    except asyncio.CancelledError:
        print("主函数捕获到取消异常")
    
    print(f"任务完成状态: {task.done()}")      # True
    print(f"任务被取消: {task.cancelled()}")   # True

asyncio.run(cancel_demo())
# 示例3_task.add_done_callback(func)
import asyncio

async def my_coroutine_1():
    print("协程1开始")
    await asyncio.sleep(2)
    print("协程1结束")
    return "结果1"

async def my_coroutine_2():
    print("协程2开始")
    await asyncio.sleep(3)
    print("协程2结束")
    return "结果2"

def check_task(future):
    
    # 注意:这里需要访问 task1,所以要用全局变量或闭包
    global task1_global
    if task1_global.done():
        print("task1 已经完成")
    else:
        print("task1 还未完成")

async def main():
    global task1_global
    
    # 创建任务
    task1 = asyncio.create_task(my_coroutine_1())
    task2 = asyncio.create_task(my_coroutine_2())
    
    # 保存 task1 的引用给回调函数使用
    task1_global = task1
    
    # 立即注册回调(在任务可能完成之前!)
    task2.add_done_callback(check_task)
    
    # 等待所有任务完成
    result1 = await task1
    result2 = await task2  # 这行其实可以省略,因为 task2 已经完成了
    
    print(f"最终结果: {result1}, {result2}")

asyncio.run(main())

4. Future 对象

Task 与 Future 的关系

  • Task 继承自 Future,是 “可执行的 Future”(绑定了协程)。

  • Future 更底层,通常用于手动管理异步操作结果(如包装回调式 API)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值