多任务
多任务的实现方式,使用下面方法中的一个或者若干个进行组合:
1、多进程
2、多线程
3、协程
三种方式的实现和资源占用各有不同,其中资源占用和实现所需的系统开销(内存、cpu等)逐渐减少,实现难度依次降低。
可以简单的认为:一个进程可以包含多个线程,一个线程包含多个协程。
多任务实现方式的选择:
cpu密集型任务:使用多进程
io密集型:使用多线程或协程
同步与异步:
同步:代码按照顺序执行,即前面一行代码执行完成才执行下一行代码,否则需要等待(阻塞)。
异步:后面代码无需等待(非阻塞)前面代码执行完即可执行。
并发:简单地理解为cpu数量小于进程数。
并行:简单地理解为cpu数量大于或等于进程数。
协程
协程的发展:python2时期的生成器(yield、yiled from)函数,到了python3进一步封装为async、await关键字实现的方法。
包含yield关键字的函数即为生成器函数。
生成器的调用:使用for循环或者next(生成器);
与生成器的数据交互:使用生成器的send方法;
关闭生成器:close方法。
生成器执行过程:
def mtd():
a = 1
x = 2
while True:
x = yield a
a += 1
if a > 10:
break
print(x)
y = mtd()
next(y)
y.send(2)
执行顺序:
next --> 返回 a值1 --> send 2 --> x = 2 --> print 2
yield from 返回生成器对象(或者生成器函数的返回(return)值)
基本用法:
lis = [1, 2, 3]
def generator_2(lis):
yield from lis
z=generator_2(lis)
type(z) # <generator object generator_2 at 0x0000016D1953D5E8>
复杂用法:
# 子生成器
def generator_1():
total = 0
while True:
x = yield
print('加', x)
if not x: # if not None: True
break
total += x
return total
# 委托生成器
def generator_2():
while True:
# 建立调用方和子生成器的通道
total = yield from generator_1() # 子生成器
print('加和总数是:', total)
# 调用方
def main():
g2 = generator_2()
g2.send(None)
g2.send(2)
g2.send(3)
g2.send(None)
if __name__ == '__main__':
main()
第三方模块
由于是第三方模块,需要安装
pip install greenlet
pip install gevent
gevent
import gevent
from gevent import monkey
monkey.patch_all() # 为下面的requests模块打补丁,进行重写和封装
import requests
def download(url):
print("get: %s" % url)
res = requests.get(url)
data = res.text
print(len(data), url)
# 多任务
g1 = gevent.spawn(download, 'https://www.a.com/') # 创建协程
g2 = gevent.spawn(download, 'https://www.b.com/')
g3 = gevent.spawn(download, 'https://www.c.com/')
g1.join()#等待协程结束
g2.join()
g3.join()
# 另一种实现方法
#gevent.joinall([
gevent.spawn(download, 'https://www.a.com/'),
gevent.spawn(download, 'https://www.b.com/'),
gevent.spawn(download, 'https://www.c.com/')
])
greenlet
from greenlet import greenlet
import time
# 协程利用程序的IO 来切换任务
def demo1():
while True:
print("demo1")
gr2.switch()
time.sleep(0.5)
def demo2():
while True:
print("demo2")
gr1.switch()
time.sleep(0.5)
gr1 = greenlet(demo1)
gr2 = greenlet(demo2)
gr1.switch() # 启用协程
序列合并:
from itertools import chain
lis = [1, 2, 3]
dic = {
"name": "juran",
"age": 18
}
print(list(chain(lis, dic, range(5, 10))))