?人不敬我是我无才,我不敬人是我无德
-- to be a good man
前言
掌握协程的学习过程
?
协程之迭代器
1、可迭代对象iter:如列表、字符串、元组、字典、集合等,除了数字类型。
2、迭代器:创建迭代器过程
class Person:
def __init__(self):
self.students = []
self.cur_i = 0
def add(self, name):
self.students.append(name)
# iter内置方法使这个类的实例化对象变成可迭代对象
def __iter__(self):
return self
# next方法使可迭代对象变为迭代器
def __next__(self):
if self.cur_i < len(self.students):
ret = self.students[self.cur_i]
self.cur_i += 1
return ret
else:
raise StopIteration
if __name__ == '__main__':
p = Person()
p.add('kitty')
p.add('qiaqia')
p.add('bongbong')
for i in p:
print(i)
迭代器小结1:迭代器一定是可迭代对象,可以进行迭代【因为迭代器有两个方法:iter和next】;可迭代对象不一定是迭代器【因为可迭代对象只有iter方法】
迭代器小结2:迭代器比列表循环要更节省空间;迭代器好比生成的目标的方式,而列表循环是生成目标的结果
迭代器小结3:除了for循环可以接收可迭代对象之外,list、tuple类型转换也可以
协程之生成器
1、生成器是一种特殊的迭代器。
生成器实现的两种方式
# 实现方式一:通过列表推导式并将列表改为元组
def methodone():
gen = (x for x in range(6))
# print(gen)
print(next(gen))
# 实现方式二:通过包含yield关键字的函数
def methodtwo(num):
a, b = 0, 1
count = 0
while count < num:
yield a
a, b = b, a+b
count += 1
if __name__ == '__main__':
methodone()
me = methodtwo(5)
print(next(me))
生成器小结1:yield关键字,让函数变为生成器模板;?
生成器小结2:调用包含yield关键字的函数时,是创建了一个生成器对象
协程之yield、greenlet、gevent
可以理解为 gevent是对greenlet的二次封装,greenlet是对yield的二次封装,greenlet需要人工切换多任务,而gevent是自动切换多任务;目前使用场景比较多的是gevent。
import random
import time
import gevent
from gevent import monkey
# 使用该方法完成多任务自动切换
monkey.patch_all()
def fun1(msg):
for i in range(5):
print(msg, i)
time.sleep(random.random())
def main():
gevent.joinall([
gevent.spawn(fun1, 'first'),
gevent.spawn(fun1, 'second')
])
if __name__ == '__main__':
main()
协程小结 1:gevent实现协程,在遇到目标函数的时候,会自动判断函数内是否有延时,如果有,就自动切换至其他函数内执行任务;
协程小结 2:协程来实现多任务是在单个线程内,去切换不同的函数,所以对资源的消耗比较少;
场景展示一:
python使用locust进行性能测试的时候,就是利用的协程原理
场景展示二:
使用python的协程多任务完成对某个网页所有有关你想要的图片的获取并下载: 附代码及最终呈现截图
import os
import re
import gevent
import requests
# 执行下载图片到本地功能
def download(download_folder, url):
images = download_folder + '/' + url[-30:-12] + '.png'
try:
req = requests.get(url=url).content
except:
pass
with open(images, 'wb') as f:
f.write(req)
# 获取某个网站页面上的所有有关小姐姐的图片URL
def get_img_url():
req = requests.get(url='https://www.douyu.com/g_yz', verify=False)
req_list = req.text.split('<img loading="lazy" src=')
url_only = []
for url in req_list:
req = re.match(r'.+?(https.+?png/dy1).+?',url)
if req:
url_only.append(req.group(1))
return url_only
def main():
# 创建一个指定的文件夹用来存放下载的图片
download_folder = r'E:\xxxx\images'
try:
os.mkdir(download_folder)
except:
pass
urls = get_img_url()
for url in urls:
gevent.joinall([gevent.spawn(download, download_folder, url),])
if __name__ == '__main__':
main()
下载图:
?
|