Python中如何将同步调用等待的代码修改成异步执行

Python 程序调用了一些 c++导出的函数,这些函数大多会访问网络,会阻塞等待。

因为一些原因,现在无法修改那部分代码,所以我考虑用 thread / gevent 来在 python 里面实现异步操作。

直接把处理函数丢给 thread/gevent 里面去处理,这样主线程 UI 也不会阻塞住,在处理完成后,通知主线程去处理数据结果。

对 Python 不熟,请问有什么更好的方法吗?
Python中如何将同步调用等待的代码修改成异步执行

7 回复

1.C 代码是用不了 gevent 的。 gevent 是套住 Python 的 IO 操作
2.thread 大概没问题


import asyncio
import time

# 原始同步代码
def sync_task(name: str, delay: int):
    """模拟耗时同步任务"""
    print(f"{name}: 开始执行,需要{delay}秒")
    time.sleep(delay)  # 同步阻塞
    print(f"{name}: 执行完成")
    return f"{name}的结果"

# 修改后的异步版本
async def async_task(name: str, delay: int):
    """异步版本的任务"""
    print(f"{name}: 开始执行,需要{delay}秒")
    await asyncio.sleep(delay)  # 异步等待,不阻塞事件循环
    print(f"{name}: 执行完成")
    return f"{name}的结果"

# 同步执行示例(串行)
def sync_main():
    start = time.time()
    result1 = sync_task("任务1", 2)
    result2 = sync_task("任务2", 1)
    print(f"同步执行结果: {result1}, {result2}")
    print(f"总耗时: {time.time() - start:.2f}秒")

# 异步执行示例(并发)
async def async_main():
    start = time.time()
    # 创建两个并发任务
    task1 = asyncio.create_task(async_task("任务1", 2))
    task2 = asyncio.create_task(async_task("任务2", 1))
    
    # 等待所有任务完成
    result1 = await task1
    result2 = await task2
    
    print(f"异步执行结果: {result1}, {result2}")
    print(f"总耗时: {time.time() - start:.2f}秒")

# 运行对比
if __name__ == "__main__":
    print("=== 同步执行 ===")
    sync_main()  # 总耗时约3秒
    
    print("\n=== 异步执行 ===")
    asyncio.run(async_main())  # 总耗时约2秒(并发执行)

核心修改点:

  1. 函数定义:在def前加async关键字声明异步函数
  2. 阻塞调用替换:将time.sleep()换成await asyncio.sleep()
  3. 执行方式:使用asyncio.create_task()创建并发任务,用await等待结果
  4. 入口点:通过asyncio.run()启动异步主函数

关键区别:

  • 同步代码中time.sleep(2)会阻塞整个线程2秒
  • 异步代码中await asyncio.sleep(2)只会暂停当前协程,事件循环可以继续执行其他任务

适用场景:

  • I/O密集型操作(网络请求、文件读写、数据库查询)
  • 需要同时处理多个耗时操作
  • Web服务器、爬虫等并发场景

一句话总结:把阻塞调用换成awaitable对象,用asyncio管理并发。

豆瓣开源了一个叫 greenify 的项目,直接二进制打 patch,你可以试一试

如果导出函数不是异步操作 Gevent 管不了,想要解决这个只能用 C 去 call Gevent 的 API

用 Cython nogil 模式调用 C++ 函数,然后在 Python 这边可以用 threading 来调用这个 Cython wrapper

跟我想的差不多,丢到线程里面去处理来解决。

有一个封装好的包 multitasking

https://github.com/ranaroussi/multitasking

回到顶部