Python协程实战:手动切换与gevent自动调度详解
本文详解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协程操作的全部内容,希望这些示例能对读者的学习有所帮助,也欢迎大家继续支持本站获取更多技术资源。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









