协程 (单线程下实现并发)
进程:资源单位
线程:执行单位
协程:单线程下实现并发
并发:切换+保存状态
程序员自己通过代码自己检测程序中的IO
一旦遇到了IO自己通过代码切换
给操作系统的感觉就是你这个线程没有任何的IO 从而提升代码的运行效率
切换+保存状态一定能够提升效率吗?
1.当任务是IO密集型的情况下 提升效率
2.当任务是计算密集型的情况下 降低效率
接下来 我们进行验证
1.在计算密集型的情况下,通过切换+保存状态 效率到底是降低了还是提升了呢?
这是串行执行的时间:
# 串行执行 0.8540799617767334
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并发执行 1.3952205181121826
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密集型的情况下,通过切换+保存状态 效率到底是降低了还是提升了呢?
首先我们需要找到一个能够识别IO的工具,遇到IO就可以自动的切换
这里我们就用到了gevent模块
这是串行的执行结果:
from gevent import monkey;monkey.patch_all()
from gevent import spawn
import time
'''
注意 gevent模块没办法自动识别 time.sleep 等io情况
需要你手动配置一个参数
'''
def heng():
print('哼!')
time.sleep(2)
print('哼!')
def ha():
print('哈!')
time.sleep(3)
print('哈!')
start = time.time()
heng()
ha()
print(time.time()-start)
#5.041796445846558
下面是通过切换+保存状态来执行 利用gevent模块
from gevent import monkey;monkey.patch_all()
from gevent import spawn
import time
'''
注意 gevent模块没办法自动识别 time.sleep 等io情况
需要你手动配置一个参数
'''
def heng():
print('哼!')
time.sleep(2)
print('哼!')
def ha():
print('哈!')
time.sleep(3)
print('哈!')
start = time.time()
g= spawn(heng)
g1 = spawn(ha)
g.join()
g1.join()
print(time.time()-start)
#3.041301727294922
明显的看出在IO密集型的情况下 切换+保存状态能够提升效率
Gevent应用举例
利用协程实现并发
实现TCP服务端的并发
server端
import socket
from gevent import monkey;monkey.patch_all()
from gevent import spawn
sk = socket.socket()
sk.bind(('127.0.0.1', 8080))
sk.listen()
def talk(conn):
while True:
try:
data = conn.recv(1024)
if len(data) == 0 :break
print(data.decode('utf-8'))
conn.send(b'hi')
except ConnectionResetError as e:
print(e)
break
conn.close()
def server():
while True:
conn,addr = sk.accept()
spawn(talk,conn)
if __name__ == '__main__':
res = spawn(server)
res.join()
client端 起了400个线程
from threading import Thread
import socket
def client():
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
while True:
sk.send(b'hello')
data = sk.recv(1024).decode('utf-8')
print(data)
for i in range(400):
t = Thread(target=client)
t.start()
来源:https://www.cnblogs.com/s686zhou/p/11363057.html