1、gevent. 在遇到io操作时会发生切换,切换gevent.joinall()中的gevent.spawn(a)去执行。
使用非gevent封装的sleep()时会发生阻塞
import gevent
import time
def a():
print("begin a",time.time())
time.sleep(1)
print("end a ",time.time())
def b():
print("begin b",time.time())
time.sleep(1)
print("end b ",time.time())
def c():
print("begin c",time.time())
time.sleep(1)
print("end c ",time.time())
if __name__ == "__main__":
gevent.joinall([
gevent.spawn(a),
gevent.spawn(b),
gevent.spawn(c),]
)
运行结果:
begin a 1466328299.3592122
end a 1466328300.3595576
begin b 1466328300.3595576
end b 1466328301.3598628
begin c 1466328301.3598628
end c 1466328302.3601925
2、使用gevent.sleep(1)时是非阻塞的。但是当然这个sleep(1)睡眠1秒还是要经历的,只是a在睡眠时可以切换到b或c去执行:
将上面的time.sleep(1)改为gevent.sleep(1)
gevent.sleep(1)
运行结果:
begin a 1466328564.0706365
begin b 1466328564.0891385
begin c 1466328564.089639
end a 1466328565.0892923
end c 1466328565.0907917
end b 1466328565.0907917
3、在文件最开始使用from gevent import monkey;monkey.patch_all() 可以使time.sleep(1)为非阻塞。这样就不用gevent的sleep(1)了。
4、gevent实现单线程socket允许同时多个连接同时发生数据。 也可以使用from gevent import socket,这样就不用使用monkey.patch_all()了。
简单示例代码:
# 服务器端
import gevent
import time
import socket
from gevent import monkey;monkey.patch_all()
def server(port):
s = socket.socket()
s.bind(('127.0.0.1',port))
s.listen(50)
# s.setblocking(False)
while True:
conn, addr = s.accept() # 接收客户端连接
print("来了一个连接:",addr)
gevent.spawn(handle_switch,conn) # gevent.spawn()里的handle_switch()内部会非阻塞状态
def handle_switch(conn):
while True:
try:
data = conn.recv(1024) # 非阻塞,并不代表会往下执行,在这里而是发生切换。
except ConnectionResetError as e:
print(e)
conn.close()
break
conn.send(data) # 非阻塞
print("recv:",data.decode())
if not data:
conn.close()
print("客户端正常关闭")
break
if __name__ == "__main__":
server(9001)
# 客户端
import socket
s = socket.socket()
s.connect(('127.0.0.1',9001))
while True:
data = input(">> ").strip()
if data == "":
continue
if data == "q":
s.close()
break
s.send(bytes(data,encoding="utf-8"))
data = s.recv(1024)
print("recv:",data.decode())
发起两个连接:
允许结果:
来了一个连接: ('127.0.0.1', 55801) # 第一个客户端连接
recv: asd
recv: asd
来了一个连接: ('127.0.0.1', 55804) # 第二个客户端连接
recv: sdfa
recv: asdg
recv: 1
recv: 1
recv: 2
recv: 2
recv: 1
recv: 2
recv: # 客户端1断开连接,data为空
客户端正常关闭 # 客户端1正常断开,即客户端是s.close()的
recv: haha
recv: # 客户端2断开连接,data为空
客户端正常关闭 # 客户端1正常断开,即客户端是s.close()的
来了一个连接: ('127.0.0.1', 55820) # 第三个客户端连接
recv: asd
[WinError 10054] 远程主机强迫关闭了一个现有的连接。 # 客户端3非正常连接,应该是被kill掉了进程,客户端发送rst包。