python 实现协程 提高效率
发布日期:2021-05-07 13:23:13 浏览次数:28 分类:精选文章

本文共 3028 字,大约阅读时间需要 10 分钟。

协程的概念与实现探析

在操作系统领域,协程的概念并非操作系统本身所定义,而是为解决单线程和单进程环境下的并发执行问题而提出的。协程的核心思想是模拟多线程的并发效果,通过代码级别的切换机制实现任务的交替执行。

协程的实现依赖于多道技术,这使得线程能够在不同的时间和空间内复用资源。具体而言,协程需要实现"保存状态+切换"的机制。然而,协程的切换仅在遇到I/O操作时进行,这样可以有效避免不必要的上下文切换开销,从而提升运行效率。值得注意的是,协程的切换位置必须准确,否则可能导致整体效率的降低。

从实现方式来看,协程主要依赖于两个关键机制:

  • yield机制:通过yield生成器保存当前状态,与操作系统保存线程状态的方式类似,但更加轻量级。
  • send机制:允许在单线程内实现程序间的切换,通过传递函数结果等方式实现任务的协同执行。
  • 然而,单纯依赖协程的切换并不能显著提升运行效率。原因在于,协程需要检测所有的I/O行为,并在遇到阻塞时进行切换。如果任何一个任务阻塞,整个线程都会停止执行,这与多线程环境下的行为有所不同。

    协程的核心目标是实现单线程环境下的并发效果。并发的本质是切换与状态保存的结合,使得多个任务看起来能够同时执行。然而,协程的实现需要严格控制I/O操作的切换点,这与多线程环境下的机制有所不同。

    基于以上背景,我们可以通过具体案例来理解协程的实际应用效果:

  • 计算型任务的协程实现
  • import time
    def func1():
    while True:
    yield
    def func2():
    g = func1()
    for i in range(10000000):
    i + 1
    next(g)
    start = time.time()
    func2()
    stop = time.time()
    print(stop - start)

    在此示例中,使用生成器实现协程的并发执行。尽管在计算型任务中,单线程执行的效率通常优于协程,但通过合理控制切换点,可以在某些场景下实现较好的性能提升。

    1. I/O型任务的协程实现
    2. import time
      def func1():
      while True:
      print('func1')
      yield
      def func2():
      g = func1()
      for i in range(10000000):
      i + 1
      next(g)
      time.sleep(3)
      print('func2')
      start = time.time()
      func2()
      stop = time.time()
      print(stop - start)

      在I/O型任务中,协程能够有效检测到I/O操作并进行切换,从而实现多任务并发。这种机制能够显著提升整体运行效率。

      真正意义上的协程实现通常依赖于第三方库,如gevent。通过对I/O操作的自动检测和切换控制,gevent能够提供更高效的协程执行模型。

      协程技术在爬虫领域的应用尤为突出。通过在单进程环境中使用协程,开发者可以同时执行多个网络请求,充分利用系统资源。

      例如:

      from gevent import monkey
      monkey.patch_all()
      import requests
      def get_page(url):
      print(f'GET: {url}')
      response = requests.get(url)
      if response.status_code == 200:
      print(f'{len(response.text)} bytes received from {url}')
      start_time = time.time()
      gevent.joinall([
      gevent.spawn(get_page, 'https://www.python.org/'),
      gevent.spawn(get_page, 'https://www.yahoo.com/'),
      gevent.spawn(get_page, 'https://github.com/'),
      ])
      stop_time = time.time()
      print(f'run time is {stop_time - start_time}')

      在socket通信中,协程实现同样具有显著优势。通过gevent的补丁机制,可以实现I/O切换的自动检测,从而实现高效的协程执行。

      服务端示例

      from gevent import monkey
      monkey.patch_all()
      from socket import *
      def server(server_ip, port):
      s = socket(AF_INET, SOCK_STREAM)
      s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
      s.bind((server_ip, port))
      s.listen(5)
      while True:
      conn, addr = s.accept()
      gevent.spawn(talk, conn, addr)
      def talk(conn, addr):
      try:
      while True:
      res = conn.recv(1024)
      print(f'client {addr[0]}:{addr[1]} msg: {res}')
      conn.send(res.upper())
      except Exception as e:
      print(e)
      finally:
      conn.close()
      if __name__ == '__main__':
      server('127.0.0.1', 8080)

      客户端示例

      from socket import *
      client = socket(AF_INET, SOCK_STREAM)
      client.connect(('127.0.0.1', 8080))
      while True:
      msg = input('> >: ').strip()
      if not msg:
      continue
      client.send(msg.encode('utf-8'))
      msg = client.recv(1024)
      print(msg.decode('utf-8'))

      相比多线程实现,协程在socket通信中的优势在于切换机制的更高效。然而,协程的实现需要谨慎取舍,特别是在计算型任务中,可能需要结合多线程和协程的混合使用,以实现最佳性能。

      总体而言,协程技术为单线程环境下的并发执行提供了一种高效的解决方案。通过合理控制切换点和利用适当的工具,开发者可以充分发挥协程的优势,从而在实际应用中实现高效的多任务执行。

    上一篇:python爬虫实战项目,做完直接进阶
    下一篇:pycharm 安装保姆级别教程(手把手教学安装)

    发表评论

    最新留言

    能坚持,总会有不一样的收获!
    [***.219.124.196]2025年03月22日 18时09分20秒