理论
python中多任务的实现可以使用进程、线程或协程。
协程是单线程下的并发,又称微线程、纤程,比线程更小,占用更小的执行单元。
协程是用户程序自己控制调度的,在计算机层面并没有协程,而是程序员根据代码实现的CPU的切换。
实践
1、yield实现上下文切换
import time
def job1():
for i in range(4):
print('--------job1-------', time.time() - start)
yield
time.sleep(1)
def job2():
for i in range(4):
print('--------job2-------', time.time() - start)
yield
time.sleep(1)
if __name__ == '__main__':
start = time.time()
j1 = job1()
j2 = job2()
for i in range(3):
next(j1)
next(j2)
print(time.time() - start)
运行结果
--------job1------- 4.0531158447265625e-06
--------job2------- 4.601478576660156e-05
--------job1------- 1.0011780261993408
--------job2------- 2.001481056213379
--------job1------- 3.00597882270813
--------job2------- 4.011059045791626
4.011122941970825
2、greenlet实现上下文切换
import greenlet
import time
def job1():
for i in range(3):
print('--------job1-------', time.time() - start)
j2.switch()
time.sleep(1)
def job2():
for i in range(3):
print('--------job2-------', time.time() - start)
j1.switch()
time.sleep(1)
if __name__ == '__main__':
start = time.time()
j1 = greenlet.greenlet(job1)
j2 = greenlet.greenlet(job2)
j1.switch()
print(time.time() - start)
运行结果
--------job1------- 1.0013580322265625e-05
--------job2------- 5.1975250244140625e-05
--------job1------- 1.0030829906463623
--------job2------- 2.0068538188934326
--------job1------- 3.0111947059631348
--------job2------- 4.015782833099365
5.018911838531494
3、gevent实现协程
在上面的代码中,yield和greenlet仅实现代码上下文的切换,还算不上协程。
在下面的代码中,使用gevent.sleep()代替time.sleep()模拟耗时操作,原因是在程序中有耗时操作时,需要将耗时操作代码替换为gevent中自己实现的代码,才能自动切换协程。
import gevent
import time
def job1():
for i in range(3):
print('--------job1-------', time.time() - start)
gevent.sleep(1)
def job2():
for i in range(3):
print('--------job2-------', time.time() - start)
gevent.sleep(1)
if __name__ == '__main__':
start = time.time()
j1 = gevent.spawn(job1, )
j2 = gevent.spawn(job2, )
gevent.joinall([j1, j2])
print(time.time() - start)
运行结果
--------job1------- 0.0005421638488769531
--------job2------- 0.0006239414215087891
--------job1------- 1.0010240077972412
--------job2------- 1.001089096069336
--------job1------- 2.003490924835205
--------job2------- 2.0035531520843506
3.0075089931488037
4、gevent+猴子补丁实现协程
在实际开发中,将会面对许多复杂的情况,我们实现协程时尽量不去修改原有的代码,所以gevent模块中提供了一个猴子补丁,帮开发人员实现自动将耗时代码替换成gevent自己实现的模块。
import gevent
from gevent import monkey
import time
monkey.patch_all()
def job(a):
for i in range(3):
print(f'--------job{a}-------', time.time() - start)
time.sleep(1)
if __name__ == '__main__':
start = time.time()
j1 = gevent.spawn(job, 1)
j2 = gevent.spawn(job, 2)
gevent.joinall([j1, j2])
print(time.time() - start)
运行结果
--------job1------- 0.00033593177795410156
--------job2------- 0.00041413307189941406
--------job1------- 1.0042319297790527
--------job2------- 1.004328966140747
--------job1------- 2.00445818901062
--------job2------- 2.004521131515503
3.006899118423462
文章介绍了Python中实现多任务的几种方式,包括使用yield、greenlet和gevent库。通过示例展示了如何通过这些方法进行上下文切换,实现并发执行。特别是gevent,它能自动处理耗时操作,提高程序效率。
527

被折叠的 条评论
为什么被折叠?



