标签:控制 不能 因此 程序 就是 猴子补丁 并发编程 简化 切换
目录
? 在单个线程下实现并发效果,在多个任务之间切换。协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置,当程序中存在大量不需要CPU的操作时(IO),适用于协程。
? 官方说法:协程称为微线程,就是操作系统级别的线程。是由操作系统来控制调度的。
GIL锁 导致多线程无法并行执行,只能并发执行,效率低。但是并发时我们要实现的最终目的(最好并行)
例如tcp服务器,限制了最大线程数量1000,如果第1000个客户有一部分,没有进行任何的操作,而新任务将无法被处理,即使CPU空闲
协程有极高的执行效率,因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销
不需要多线程的锁机制,因为只有一个线程,不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了。所以执行效率比多线程高很多。
因为协程是一个线程执行,所以想要利用多核CPU,最简单的方法是多进程+协程,这样既充分利用多核,又充分发挥协程的高效率。
import greenlet
def task1():
print("task1 start")
time.sleep(2)
print("task1 over")
def task2():
print("task2 start")
time.sleep(2)
print("task2 over")
g1 = greenlet.greenlet(task1)
g2 = greenlet.greenlet(task2)
start_time = time.time()
g1.switch() # 可以理解为:开始g1协程,执行完毕后,开始g2协程
g2.switch() # 开始g2协程
end_time = time.time() - start_time
print(end_time)
task1 start
task1 over
task2 start
task2 over
4.000658273696899
不作为的情况下,就是串行。
import greenlet
def task1():
print("task1 start")
g2.switch() # 下面即将面对IO操作。于是切换到g2协程
time.sleep(2)
print("task1 over")
g2.switch() # g1协程执行完毕,切换到g2协程
def task2():
print("task2 start")
g1.switch() # 下面即将面对IO操作。于是切换到g1协程
time.sleep(2)
print("task2 over")
g1 = greenlet.greenlet(task1)
g2 = greenlet.greenlet(task2)
# 计算时间
start_time = time.time()
g1.switch() # 开启g1协程.这里注意g2协程已经在g1协程中开启了。所有在外面无需再开了
end_time = time.time() - start_time
print(end_time)
task1 start
task2 start
task1 over
task2 over
4.000972509384155
import greenlet
def task1():
print("task1 start")
g2.switch()
for i in range(50000000):
1 + 1
print("task1 over")
g2.switch()
def task2():
print("task2 start")
g1.switch()
for i in range(50000000):
1 + 1
print("task2 over")
g1 = greenlet.greenlet(task1)
g2 = greenlet.greenlet(task2)
# 计算时间
start_time = time.time()
g1.switch()
end_time = time.time() - start_time
print(end_time)
task1 start
task2 start
task1 over
task2 over
2.6845099925994873
import greenlet
def task1():
print("task1 start")
for i in range(50000000):
1 + 1
print("task1 over")
def task2():
print("task2 start")
for i in range(50000000):
1 + 1
print("task2 over")
g1 = greenlet.greenlet(task1)
g2 = greenlet.greenlet(task2)
# 计算时间
start_time = time.time()
g1.switch()
g2.switch()
end_time = time.time() - start_time
print(end_time)
task1 start
task2 start
task1 over
task2 over
2.6445099925994873
from gevent.monkey import patch_all # 猴子补丁。geven实现并发的原理,是将原本阻塞的代码变为非阻塞
import gevent
import time
patch_all() # 对导入的模块进行打补丁
def task1():
print("task1 start")
time.sleep(2) # 遇到阻塞操作,切换到另外一个任务
print("task1 over")
def task2():
print("task2 start")
time.sleep(2) # 遇到阻塞操作,切换到另外一个任务
print("task2 over")
g1 = gevent.spawn(task1)
g2 = gevent.spawn(task2)
# 计算时间
start_time = time.time()
g1.join() # 开启一个 就能让所有的协程进行工作
end_time = time.time() - start_time
print(end_time)
task1 start
task2 start
task1 over
task2 over
2.003842830657959
from gevent.monkey import patch_all
import gevent
import time
patch_all()
def task1():
print("task1 start")
for i in range(50000000): # 此时遇到的不是IO操作,而是计算,因此协程不会切换,而是直接执行完
1 + 1
print("task1 over")
def task2():
print("task2 start")
for i in range(50000000):
1 + 1 # 此时遇到的不是IO操作,而是计算,因此协程不会切换,而是直接执行完
print("task2 over")
g1 = gevent.spawn(task1)
g2 = gevent.spawn(task2)
# 计算时间
start_time = time.time()
g1.join() # 开启一个 就能让所有的协程进行工作
end_time = time.time() - start_time
print(end_time)
task1 start
task1 over
task2 start
task2 over
2.5767011642456055
因此,协程使用gevent模块更好!
标签:控制 不能 因此 程序 就是 猴子补丁 并发编程 简化 切换
原文地址:https://www.cnblogs.com/plf-Jack/p/11153098.html