1.创建一个生成器:
next和send都可以使生成器对象输出。
区别在send可以传值。
def create_num(all_num):
print('-----1-------')
a, b = 0, 1
current_num = 0
while current_num < all_num:
print('-----2-----')
ret = yield a
print('>>>>ret>>>>',ret)
print('-----3------')
a, b = b, a + b
current_num += 1
print('-----4------')
return 'ok'
obj1 = create_num(100)
print('obj1:',obj1)
red = next(obj1)
print(red)
red1 = obj1.send('python')
print(red1)
2.生成器的应用:实现多任务
import time
def task_1():
while True:
print('-----1-------')
time.sleep(0.1)
yield
def task_2():
while True:
print('-------2---------')
time.sleep(0.1)
yield
# task_1()
# task_2()
def main():
t1 = task_1()
t2 = task_2()
"""
类似于两个while True一起执行
先让t1运行一会,当t1遇到yield的时候,再返回到18行
然后执行t2,当它遇到yield的时候,再次切换到t1中
这样t1/t2/t1/t2的交替运行,最终实现了多任务---->协程
"""
while True:
next(t1)
next(t2)
main()
"""
并行:有两个任务,两个cpu,一个任务占一个cpu
并发:有四个任务,两个cpu,四个任务交替占有cpu执行,我们这里实现的都是并发
"""
3.yield实现单线程并发
上面的例子定义了两个函数,是多线程的并发那么怎么让单线程并发呢?
利用了关键字yield一次性返回一个结果,阻塞,重新开始
send 唤醒
这个例子实现了单线程两个函数同时并发。
import time
def consumer(name):
print('%s 准备学习了' % (name))
while True:
lesson = yield
print('开始[%s]了,[%s]老师来讲课了' % (lesson, name))
def producer(name):
c1 = consumer('A') # 并发 调用函数,打印AB准备学习了,到yield暂停
c2 = consumer('B')
c1.__next__() # 与函数外next的同理只是格式不同,让consumer程序从yield循环一次。yield输出值none这里没有打印,所以没有输出。
c2.__next__()
print('同学们开始上课了')
for i in range(10):
time.sleep(0.1)
print('到了两个同学')
c1.send(i) # 将i传递给断点处 lesson = 0 ,这里满足了send不在第一个,next的none是yield的第一个输出。
c2.send(i) # 并发lesson = 0
producer('westos')
4.使用greenlet完成多任务
为了更好的使用协程来完成多任务,python中的greeblet模块
对其进行的封装
首先先在系统里安装greenlet
from greenlet import greenlet
import time
def test1():
while True:
print('---A---')
gr2.switch() # 与test2交替进行,当test1暂停的时候,执行test2,
# test2暂停时执行test1
time.sleep(0.5)
def test2():
while True:
print('---B---')
gr1.switch()
time.sleep(0.5)
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch() #这里一定要到按这个格式调用函数
5.使用gevent完成多任务
和greenlet一样,先下在gevent第三方库
gevent也能实现函数的交替进行,当一个函数暂停时运行下一个。
这里为了看出效果,我们让f3不睡眠,f1,f2睡眠。
可以看出f1睡眠0.5s时运行f2,f2睡眠0.5s运行f3,
因为f3不睡眠所以运行到结束才会接着运行f1。
import gevent
def f1(n):
for i in range(n):
print(gevent.getcurrent(),i)
gevent.sleep(0.5)
def f2(n):
for i in range(n):
print(gevent.getcurrent(),i)
gevent.sleep(0.5)
def f3(n):
for i in range(n):
print(gevent.getcurrent(),i)
#gevent.sleep(0.5) f3函数不睡眠0.5秒
g1 = gevent.spawn(f1,5)
g2 = gevent.spawn(f2,5)
g3 = gevent.spawn(f3,5)
g1.join()
g2.join()
g3.join()
从结果可以看出f3()运行完才继续交替运行f1,f2.
6.利用并行可以进行同时下载网页的多个图片
首先,学习一下单张图片的下载。
首先选择你要下载的图片–>按f12显示web代码–>找到图片对应的网址
找到图片地址,以jpg结尾。
https://img30.360buyimg.com/vc/jfs/t26584/137/2237011912/642049/b9bd9596/5bfb9442Ncb0c29fc.jpg
import urllib.request
def main():
req = urllib.request.urlopen('https://img30.360buyimg.com/vc/jfs/t26584/137/2237011912/642049/b9bd9596/5bfb9442Ncb0c29fc.jpg')
img_content = req.read()
with open('python.jpg','wb') as f: #定一个图片名为python
f.write(img_content)
main()
可以在当前文件夹下看见多了一个名为python的文件
图片下载成功
可以利用gevent一次下载多张图片:
import urllib.request
import gevent
from gevent import monkey
def downloder(img_name,img_url):
req = urllib.request.urlopen(img_url)
img_content = req.read()
with open(img_name,'wb') as f:
f.write(img_content)
def main():
gevent.joinall([
gevent.spawn(downloder,'2.jpg','https://img3.doubanio.com/view/photo/m/public/p2528834770.jpg'),
gevent.spawn(downloder,'3.jpg','https://img1.doubanio.com/view/photo/l/public/p2541840518.jpg'),
gevent.spawn(downloder,'4.jpg','https://img3.doubanio.com/view/photo/l/public/p2540519750.jpg')
])
main()