需求:使用一个线程,去请求多个网站的资源(注意,请求上会有延时)<其实是去请求了大量的网站信息,咱们使用了多线程,只不过每一个线程依旧会分配到多个网站资源,这里咱们只须要去讨论这一条线程便可>
能够看出,因为网络延迟等因素,当咱们去获取信息时,有一段时间呗浪费,用于空等信息返回,当咱们去获取大量网站的时候,那这个时间是很是大的。咱们须要去避免他。
解决方案:使用协程,充分利用咱们中间等待的这一段时间,去作其余的事情,好比其请求下一个网站,,或者下几个网站。而后连续去接收信息,就能够充分的利用空耗的时间
pip3 install gevent # gevent模块如果没有,只须要先下载
开始使用:网络
import gevent
from gevent import monkey
monkry.patch_all() #能够提升效率
def foo(): print("foo函数开始运行") gevent.sleep(0) print("又回到了foo函数") def bar(): print("bar函数开始运行") gevent.sleep(0) print("又回到了bar函数") gevent.joinall([ gevent.spawn(foo), gevent.spawn(bar), ])
输出结果:
foo函数开始运行
bar函数开始运行
又回到了foo函数
又回到了bar函数
import gevent import time begin = time.time() def foo(): fs = time.time() - begin print("foo函数开始运行",fs)
gevent.sleep(3) fe = time.time() - begin print("又回到了foo函数",fe) def bar(): bs = time.time() - begin print("bar函数开始运行",bs)
gevent.sleep(3)
be = time.time() - begin print("又回到了bar函数",be) gevent.joinall([ gevent.spawn(foo), gevent.spawn(bar), ])
foo函数开始运行 0.01000070571899414 bar函数开始运行 0.01000070571899414 又回到了foo函数 3.0101723670959473 又回到了bar函数 3.0101723670959473
注意输出结果多线程
咱们能够看出两个函数都是在统一时间执行第一句输出,在三秒后去执行的第二句输出框架
import gevent import time begin = time.time() def foo(): fs = time.time() - begin print("foo函数开始运行",fs)
gevent.sleep(1) fe = time.time() - begin print("又回到了foo函数",fe) def bar(): bs = time.time() - begin print("bar函数开始运行",bs)
gevent.sleep(3)
be = time.time() - begin print("又回到了bar函数",be) gevent.joinall([ gevent.spawn(foo), gevent.spawn(bar), ])
注意输出结果:几乎在同一时间执行两个函数(顺序和joinall方法中注册顺序有关),在咱们设定的sleep时间后去继续执行函数函数
foo函数开始运行 0.0060002803802490234 bar函数开始运行 0.0060002803802490234 又回到了foo函数 1.0060575008392334 又回到了bar函数 3.006171941757202
因此说对于最上面简单使用中的执行顺序先是根据joinall的注册顺序去打印网站
foo函数开始运行
bar函数开始运行
而后因为sleep(0)间隔是0,因此当即去执行下面的打印程序(当sleep的时间是一致时,顺序仍是和注册时一致)url
又回到了foo函数
又回到了bar函数
import gevent import time begin = time.time() def foo(): fs = time.time() - begin print("foo函数开始运行",fs)
gevent.sleep(1)
time.sleep(4) #这里睡眠4秒 fe = time.time() - begin print("又回到了foo函数",fe) def bar(): bs = time.time() - begin print("bar函数开始运行",bs)
gevent.sleep(3)
be = time.time() - begin print("又回到了bar函数",be) gevent.joinall([ gevent.spawn(foo), gevent.spawn(bar), ])
注意输出结果:发现对于咱们在foo中设置的time.sleep(4)对bar方法也有影响。spa
foo函数开始运行 0.005000114440917969 bar函数开始运行 0.0060002803802490234 又回到了foo函数 5.006286144256592 又回到了bar函数 5.007286310195923
缘由:gevent设置了咱们协程的苏醒时间,可是当苏醒时间与咱们的执行时间相冲突,那么会以执行时间为主(毕竟这是单线程,不会考虑其余的),而原来的设置的gevent.sleep(秒数)则变成了大小比较,谁在后,谁就后执行线程
import gevent import time begin = time.time() def foo(url,index): fs = time.time() - begin print("%s:发送请求到%s,等待返回"%(index,url),fs) #这里能够模拟发送请求 gevent.sleep(0) fe = time.time() - begin print("%s:获取信息从%s,开始处理"%(index,url),fe) #这里模拟处理信息 gevent.joinall([ gevent.spawn(foo,"www.baidu.com",1), #注意传参方式 gevent.spawn(foo,"www.sina.com.sn",2), ])
输出结果:3d
1:发送请求到www.baidu.com,等待返回 0.005000114440917969 2:发送请求到www.sina.com.sn,等待返回 0.005000114440917969 1:获取信息从www.baidu.com,开始处理 0.005000114440917969 2:获取信息从www.sina.com.sn,开始处理 0.005000114440917969
from greenlet import greenlet def foo(): print("开始执行foo") gr2.switch() print("又回到foo") gr2.switch() def bar(): print("开始执行bar") gr1.switch() print("又回到bar") gr1 = greenlet(foo) gr2 = greenlet(bar) gr1.switch() #以gr1开始执行,switch中也能够传递参数
输出结果:code
开始执行foo
开始执行bar
又回到foo
又回到bar