学习笔记之四十五
并发中,进程或线程只要 一sleep,就会转让执行权出去已占用的cpu资源,Python中线程是伪多线程,因为解释器底层的锁GIL,只要创建线程就有 全局解释器锁;别的语言中需要锁时才申请加锁;
协程
协程:又叫微线程,是Python特有的,为了当有一个协程阻塞停滞时,快速切换到其他协程运行,保证cpu的高效运转,任务快速完成,
协程实现方法有三种:
1、生成器完成,
2、greenlet (第三方包)完成,
3、gevent.spawn完成,
greenlet已经实现了协程,但是这个需要人工切换,比较麻烦,Python还有一个强大而且能够自动切换任务的模块,
gevent,其原理相当于 当一个greenlet遇到IO(指输入,输出,网络、文件操作等耗时任务)操作时,比如访问网络,就自动化切换到其他的greenlet,等到IO完成,在适当的时候再切换回来继续执行,
由于IO操作非常耗时,经常使程序处于等待状态,有了gevent我们自动切换协程,就保证总有greenlet在运行,(cpu一种在运行状态,为浪费静止),而不是等待IOUrl 和path时一个意思,路径 ,比如文件路径等;
访问网络的强大模块:requests,但是不如其的类似作用的模块有 urllib,其获得方法 response=urllib.read()
协程:微线程
进程-线程-协程
进程-模块multiprocessing中的Process类 创建运行
线程-模块multithread中的Thread类创建运行
协程:生成器完成
import time
def task1():
for i in range(3):
print(‘A’+str(i))
yield
time.sleep(0.2)
def task2():
for i in range(3):
print(‘A’+str(i))
yield
time.sleep(0.2)
if name==‘main’:
g1=task1()
g2=task2()
while True:
try:
next(g1)
next(g2)
except:
break
上述代码先将生成器g1全部执行完毕,在执行g2,在两个生成器的sleep时间内没有切换执行任务,从而导致cpu的浪费,任务完成吧缓慢;由上引入了greenlet 模块,第三方包,需要下载:如下代码
def task1(): #任务A
for i in range(3):
print(‘A’+str(i))
time.sleep(0.2)
def task2(): #任务B
for i in range(3):
print(‘A’+str(i))
gb.switch()
time.sleep(0.2)
def task3(): #任务C
for i in range(3):
print(‘A’+str(i))
gb.switch()
time.sleep(0.2)
if name==;main’:
ga=greenlet(a)
ga=greenlet(b)
ga=greenlet©
ga.switch()
#表示任务Asleep时主动切换,但是只是A任务运行耗时时刻切换,BC不能,所以在BC任务中也加切换语句
greenlet虽然能实现切换,但需要手动加代码切换,为了更方便引入了gevent方法(也是第三方包)但是gevent模块必须同时引入猴子补丁,如下
import geventfrom gevent
import monkey
monkey.patch_all() #表示遇到IO,网络下载等耗时阻塞时,自动切换且休眠时间(sleep)更换为gevent底层设定的时间
def task1():#任务A
for i in range(5):
print(‘A’+str(i))
time.sleep(0.2)
def task1():#任务B
for i in range(5):
print(‘A’+str(i))
time.sleep(0.2)
def task1(): #任务C
for i in range(5):
print(‘A’+str(i))
time.sleep(0.2)
if name==‘main’:
g1=gevent.spawn(a)
g2=gevent.spawn(b)
g3=gevent.dpawn©
g1.join() #表示任务A在主进程中插队
g2,join()
g3.join()
pritn(‘这是主进程大打印…’)
协程案例: 爬虫的简单应用
import requestsdef download(url): response=requests.get(uel) content=response.text
print(‘下载了{}的数据,长度为:{}’.format(url,len(content))
‘’'注意:网络下载最好的模块时requests,类似作用的urllib上述定义的方法可以改写为:
def download(url): response=urllib.request.urlopen() content=response,read()
print(‘下载了{}的数据,长度为:{}’.format(url,len(content))’’’
if name==‘main’:
urls=[‘http://www.163.com’,‘http://www.qq.com’,‘http://www.baidu.com’]
g1=gevent.spawn(download.urls[0])
g2=gevent.spawn(download.urls[1])
g3=gevent.spawn(download.urls[2])
g1.join()
g2.join()
g3.join()#三个任务一起实现插队语句 :
gevent.joinall(g1,g2,g3)