Python. 协程asyncio、gevent

1、协程是一种轻量级的并发机制,允许你在单个线程内模拟并发执行多个任务。协程非常适合用于 I/O 密集型任务,如网络请求、文件读写等,在等待 I/O 操作完成时,协程可以继续执行其他任务而不是阻塞。

  1. 生成器:

    • 协程的基础是生成器(generator)。生成器是一种特殊的迭代器,它可以使用 yield 表达式暂停其执行,并在后续调用 next() 方法时恢复执行。
    • 生成器可以使用 yield 表达式返回一个值,并保存当前的状态,以便下次调用时可以从上次暂停的地方继续执行。
  2. 异步编程:

    • 协程可以用来编写异步代码,这样就可以在等待某些操作(如 I/O 操作)完成时执行其他任务。
    • Python 3.5 引入了 asyncio 模块,提供了协程和异步编程的支持。
  3. 关键字 asyncawait:

    • async def 用于定义一个协程函数。
    • await 用于在协程函数内部等待另一个协程的完成。
      import asyncio
      
      # 定义一个协程函数
      async def task(name, delay):
          print(f"{name} task starts.")
          await asyncio.sleep(delay)  # 模拟一个异步操作
          print(f"{name} task finishes.")
      
      async def main():
          # 创建并启动两个任务
          task1 = asyncio.create_task(task("Task 1", 2))
          task2 = asyncio.create_task(task("Task 2", 1))
      
        # 等待所有任务完成
          # await task1
          # await task2
          await asyncio.gather(task1, task2)
      
      # 运行协程
      asyncio.run(main())

2、gevent 是一个 Python 库,它提供了一种轻量级的并发机制,使用 greenlets(绿色线程)来实现协程 

gevent 的特点

  1. 轻量级:

    • gevent 的 greenlets 是轻量级的,可以在单个线程内运行多个 greenlets。
  2. 非抢占性调度:

    • greenlets 的调度是非抢占式的,这意味着一个 greenlet 只能在遇到 switch 方法时主动让出控制权。
  3. 共享内存:

    • greenlets 共享相同的内存空间,这意味着它们可以直接访问相同的变量和数据结构。
  4. 适合 I/O 密集型任务:

    • gevent 非常适合处理 I/O 密集型任务,如网络请求、文件读写等。在等待 I/O 操作完成时,greenlet 可以继续执行其他任务。
  5. 异步编程:

    • gevent 提供了一种自然的方式来编写异步代码,使得代码更容易理解和维护。
  6. 自动猴子补丁:

    • gevent 提供了一个“猴子补丁”(monkey patching)功能,可以将 Python 的标准库中的阻塞调用替换为非阻塞的版本。
from gevent import monkey; monkey.patch_all()  # 必须在导入其他库之前执行
import gevent
import requests

def fetch_url(url):
    print(f"Fetching {url}...")
    response = requests.get(url)
    print(f"Fetched {url}: {len(response.text)} bytes")

def main():
    urls = [
        "https://www.example.com",
        "https://www.example.org",
        "https://www.example.net"
    ]
    greenlets = [gevent.spawn(fetch_url, url) for url in urls]
    
    gevent.joinall(greenlets)

if __name__ == "__main__":
    start_time = time.time()
    main()
    end_time = time.time()
    print(f"Total time taken: {end_time - start_time:.2f} seconds")

代码解释

  1. Monkey Patching:

    • monkey.patch_all() 用于自动将标准库中的阻塞调用替换为 gevent 的非阻塞版本。这是为了让 gevent 能够接管标准库中的网络请求等 I/O 操作。
  2. 定义 greenlet 函数:

    • fetch_url 函数接受一个 URL 参数,并使用 requests.get() 发送网络请求。
  3. 创建并启动 greenlets:

    • 使用 gevent.spawn() 来创建并启动 greenlets。
    • gevent.joinall() 用于等待所有 greenlets 完成。
  4. 性能测量:

    • 使用 time.time() 来记录开始和结束时间,计算总的执行时间。

gevent 与 asyncio 的区别

  • 实现方式:

    • gevent 由 gevent 库提供支持,使用 gevent.greenlet.Greenlet 类。
    • asyncio 是 Python 3.5+ 中的原生特性,使用 async/await 关键字。
  • 调度方式:

    • gevent 的调度是由 gevent 库控制的。
    • asyncio 的调度是由 Python 的异步运行时(如 asyncio)控制的。
  • 异步支持:

    • gevent 需要使用 monkey patching 来使标准库中的 I/O 操作变为非阻塞。
    • asyncio 通常与 asyncio 一起使用,提供了一套完整的异步编程模型

你可能感兴趣的:(python,python,开发语言)