任务是计算密集型,反而会降低效率
任务是IO密集型,会提升效率
1)yield能够实现保存上次运行状态,但是无法识别io
# 串行执行 import time def func1(): for i in range(10000000): i + 1 def func2(): for i in range(10000000): i + 1 start = time.time() func1() func2() stop = time.time() print(stop - start) # 基于yield并发执行 import time def func1(): while True: 10000000 + 1 yield def func2(): g = func1() for i in range(10000000): time.sleep(100) # 模拟IO,yield并不会捕捉到并自动切换 i + 1 next(g) start = time.time() func2() stop = time.time() print(stop - start)
2)单线程下实现并发
如果你能够自己通过代码层面监测你自己的io行为
并且通过代码实现切换+保存状态
单线程实现高并发
# ---------------服务端--------------------- from gevent import monkey; monkey.patch_all() from gevent import spawn import socket def communicate(conn): while True: try: data = conn.recv(1024) if len(data) == 0: break print(data.decode('utf-8')) conn.send(data.upper()) except ConnectionResetError: break conn.close() def server(): server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(5) while True: conn, addr = server.accept() spawn(communicate, conn) if __name__ == '__main__': s1 = spawn(server) s1.join() # ---------------客户端--------------------- from threading import Thread, current_thread import socket def client(): client = socket.socket() client.connect(('127.0.0.1', 8080)) n = 1 while True: data = '%s %s' % (current_thread().name, n) n += 1 client.send(data.encode('utf-8')) info = client.recv(1024) print(info) if __name__ == '__main__': for i in range(500): t = Thread(target=client) t.start()
3)gevent模块的使用
spawn:帮你管理任务的对象
gevent模块不能识别它本身以外的所有的IO行为,但是它内部封装了一个模块,能够帮助我们识别所有的IO行为
from gevent import monkey; monkey.patch_all() # 监测代码中所有io行为 from gevent import spawn # gevent本身识别不了time.sleep等不属于该模块内的io操作 import time def heng(name): print('%s 哼' % name) time.sleep(2) print('%s 哼' % name) def ha(name): print('%s 哈' % name) time.sleep(3) print('%s 哈' % name) start = time.time() s1 = spawn(heng, 'Tom') s2 = spawn(ha, 'Bob') s1.join() s2.join() # heng('Tom') # ha('Bob') print('主', time.time() - start)
4)
# 服务端 from gevent import monkey;monkey.patch_all() from socket import * # !!!后 from gevent import spawn def communicate(conn): while True: try: data = conn.recv(1024) if len(data) == 0: break conn.send(data.upper()) except ConnectionResetError: break conn.close() def server(ip, port, backlog=5): server = socket(AF_INET, SOCK_STREAM) server.bind((ip, port)) server.listen(backlog) while True: # 链接循环 conn, client_addr = server.accept() print(client_addr) # 通信 spawn(communicate,conn) if __name__ == '__main__': g1=spawn(server,'127.0.0.1',8080) g1.join() # 客户端 from threading import Thread, current_thread from socket import * def client(): client = socket(AF_INET, SOCK_STREAM) client.connect(('127.0.0.1', 8080)) n = 0 while True: msg = '%s say hello %s' % (current_thread().name, n) n += 1 client.send(msg.encode('utf-8')) data = client.recv(1024) print(data.decode('utf-8')) if __name__ == '__main__': for i in range(500): t = Thread(target=client) t.start()
阻塞IO Blocking I/O
非阻塞IO
服务端通信针对accept用s.setblocking(False)加异常捕获,cpu占用率过高
IO多路复用 multiplexing I/O
在只检测一个套接字的情况下,他的效率连阻塞IO都比不上。因为select这个中间人增加了环节。
但是在检测多个套接字的情况下,就能省去wait for data过程
异步IO Asynchronous I/O