Python协程实战:手动切换与gevent自动调度详解

Elena
Elena
发布时间:2026-10-15 | 5人浏览过
原创

本文详解Python中协程的两种实现方式:基于greenlet的手动切换与基于gevent的自动I/O切换。通过代码示例展示如何手动控制协程执行流,以及利用monkey.patch_all()实现网络请求的非阻塞自动调度,并提供完整的Socket服务器与客户端协程实例。

手动协程操作:基于greenlet的切换

首先介绍手动协程的操作方法。在Python中,可以使用greenlet库来创建和管理协程,通过显式调用switch()方法在协程之间进行切换,从而控制执行流程。


# pip install gevent
from greenlet import greenlet

def test():
  print('He ')
  gr2.switch() # 切换到test2
  print('a ')
  gr2.switch()

def test2():
  print('is ')
  gr1.switch()
  print('student.')

gr1 = greenlet(test)  # 创建一个协程
gr2 = greenlet(test2)
gr1.switch()  # 切换到gr1,也就是运行它

自动协程:gevent与I/O自动切换

接着探讨自动协程机制。当遇到I/O操作时,可以使用gevent库配合monkey.patch_all()补丁,使标准库模块变为非阻塞模式,从而实现I/O自动切换,无需手动干预协程调度。


import gevent
from gevent import monkey; monkey.patch_all()  # 导入monkey,给所有支持的模块打上补丁,变成非阻塞模块,也就是使其能够进行协程操作
def test1(n):
  print("I'm doing my homework.")
  gevent.sleep(n)     # 模拟I/O操作,gevent自动切换
  print('Keep doing my homework.')

def test2(n):
  print("I have no time to watch TV.")
  gevent.sleep(n)
  print('Stop thinking!')

def test3():
  print("Life is hard.")

# 等待 greenlets 全部结束
gevent.joinall([
  gevent.spawn(test1,3), # 创建一个新的greeenlet对象,并规划它去执行 test1(3)
  gevent.spawn(test2,1),
  gevent.spawn(test3),
])

以下是自动协程运行的输出结果展示。

I'm doing my homework. I have no time to watch TV. Life is hard. Stop thinking! Keep doing my homework.

Socket协程实例:服务器与客户端实现

下面通过一个Socket网络编程实例来演示协程的应用。该示例包含服务器端和客户端两部分代码,展示如何利用gevent处理并发连接。

服务器端代码实现如下:首先导入socket和gevent模块,并通过monkey.patch_all()进行补丁处理,使socket操作变为非阻塞。定义server函数绑定IP和端口并开始监听。在无限循环中调用s.accept()等待连接,每接收到一个连接,便使用gevent.spawn()生成一个新的协程来处理该连接。handle_request函数负责接收数据、打印并返回处理后的结果,同时处理异常和关闭连接。


import socket
import gevent
from gevent import monkey
monkey.patch_all()  # 打补丁,让所有支持的模块变成非阻塞的方法

def server(ip,port):
  s = socket.socket()  # 生成socket对象
  s.bind((ip, port))  # 绑定ip和端口
  s.listen()      # 设置监听
  while True:
    cli, addr = s.accept()       # 等待连接
    gevent.spawn(handle_request, cli)  # 对每一个连接,使用协程的方法生成greenlet

def handle_request(conn):
  try:
    while True:
      data = conn.recv(1024)  # 接收数据
      print("recv:", data)
      new = 'Hello '+ data.decode().title()
      conn.send(new.encode('utf8'))      # 返回数据
      if not data:
        conn.shutdown(socket.SHUT_WR)
  except Exception as e:
    print(e)
  finally:
    conn.close()
if __name__ == '__main__':
  server('localhost',9999)

客户端代码实现如下:创建socket对象并连接到服务器。在循环中获取用户输入,发送数据到服务器,接收服务器返回的数据并打印,最后关闭连接。


import socket
client = socket.socket()
client.connect(('localhost',9999))
while True:
  con = input('>>>:').strip()
  if len(con) ==0: continue
  client.send(con.encode('utf-8'))
  data = client.recv(1024)
  print(data.decode())
client.close()

以上即为本文关于Python协程操作的全部内容,希望这些示例能对读者的学习有所帮助,也欢迎大家继续支持本站获取更多技术资源。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表