上古卷轴5python_python 基础(五)协程 —— 微线程 greenlet gevent

文章目录

回忆进程与线程 引入

我们之前说,有比较耗时的操作得交给线程来干,因为进程是同步调用,阻塞执行,串行执行的,那么我们就要用线程,异步调用,非阻塞,并行执行,这样的话才能提升效率。

问题来了,假设线程中也有几个子任务,耗时,然后我们程序都是串行的,也就一个Thread里面的run()都是串行执行的,一个子任务,比方下载很慢,其他任务都阻塞在那,就效率又很低了。

这时的线程就好像以前的进程一样尴尬。

我们python就出来一个微线程,可以并行操作的,线程的子任务部分,也称为

携程

协程(Coroutine) cor - routine 也可以看出并行的含义

比如,我们有很多任务要做,打游戏,学习python,配朋友,这就是三个进程。在打游戏中,我有 黑暗之魂1,2,3,上古卷轴5,也就是4个线程,当然,上古卷轴5有100个mod,我需要更新100个mod,就有了100个协程。因为更新比较耗时,必须并行调用 更新mod的任务。

greenlet

python封装了库greenlet来实现协程,我们来看个例子:#-*- utf-8 -*-

from time import sleep,time

from greenlet import greenlet

def taskA():

for i in range(5):

print('A' str(i))

gB.switch()

sleep(1) # 模拟网络阻塞 耗时操作

def taskB():

for i in range(5):

print('B' str(i))

gC.switch()

sleep(1) # 模拟网络阻塞 耗时操作

def taskC():

for i in range(5):

print('C' str(i))

gA.switch()

sleep(1) # 模拟网络阻塞 耗时操作

if __name__ == "__main__":

t1 = time()

gA = greenlet(run = taskA)

gB = greenlet(run = taskB)

gC = greenlet(run = taskC)

gA.switch()

t2 = time()

print("time consume",t2-t1)

类似process thread, greenlet也必须传target参数(他命名为run参数 反正一个意思)

这里主要是实现A B C并行轮询,但是我们可以看到这样写很蠢,需要人工切换,而且效率也不算高,于是官方的greenlet不好用,就有大佬弄出来gevent库(第三方),在greenlet基础上再封装一波,可以实现自动切换。

gevent

利用spawn函数传要做的事(taskA B C),spawn有 产卵; 引发; 引起 这几个意思,有点run的含义。

注意,我们之前在进程里面遇到过,主进程启动完子进程start以后就跑路了,导致子进程也gg,这样我们就用join阻塞,让主进程别溜,这里也是同样的道理。#-*- utf-8 -*-

from time import sleep,time

from gevent import monkey,spawn

def taskA():

for i in range(3):

print('A' str(i))

sleep(1) # 模拟网络阻塞 耗时操作

def taskB():

for i in range(3):

print('B' str(i))

sleep(1) # 模拟网络阻塞 耗时操作

def taskC():

for i in range(3):

print('C' str(i))

sleep(1) # 模拟网络阻塞 耗时操作

if __name__ == "__main__":

t1 = time()

gA = spawn(run = taskA)

gB = spawn(run = taskB)

gC = spawn(run = taskC)

gA.join()

gB.join()

gC.join()

t2 = time()

print("time consume",t2-t1)

结果:A0

A1

A2

B0

B1

B2

C0

C1

C2

time consume 9.041131258010864

我们发现,

1: 并没有轮询ABC ABC 这样的啊

2: 并没有并行啊2333 其实上面的greenlet也没有实现并行??? 还是9s

monkey

我们的time不适合这个场合的,于是利用monkey.patch_all()#-*- utf-8 -*-

import time

from gevent import monkey,spawn

monkey.patch_all()

def taskA():

for i in range(3):

print('A' str(i))

time.sleep(1) # 模拟网络阻塞 耗时操作

def taskB():

for i in range(3):

print('B' str(i))

time.sleep(1) # 模拟网络阻塞 耗时操作

def taskC():

for i in range(3):

print('C' str(i))

time.sleep(1) # 模拟网络阻塞 耗时操作

if __name__ == "__main__":

t1 = time.time()

gA = spawn(run = taskA)

gB = spawn(run = taskB)

gC = spawn(run = taskC)

gA.join()

gB.join()

gC.join()

t2 = time.time()

print("time consume",t2-t1)

这里 必须time.sleep才能生效 因为monkey在背后偷偷重载替换了原生的sleep,你直接from time import sleep, monkey匹配不到

结果:A0

B0

C0

A1

B1

C1

A2

B2

C2

time consume 3.036893606185913

Process finished with exit code 0

可见,比较完美实现了并行,time consume 时间消耗 从9s 并行变成了 3s

总结

我们直接用gevent monkey就行了 其他的执行方式太麻烦了,简直就是再造轮子:)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值