先来说几个概念
同步: 代码调用IO操作时,必须等到操作完成返回的调用方式,同步是并行
异步: 代码调用IO操作时,必须等到操作完成返回的调用方式,异步是串行
阻塞: 从调用者的角度说,如果调用时被卡住,不再往下执行,需要等待就是说阻塞
非阻塞: 从调用者的角度说,如果调用时没有被卡住,继续往下执行无需等待就是说非阻塞
生成器—send方法
- 启动生成器
- 发送值给生成器返回
def generator(num):
a, b = 0, 1
con = 0
while con < num:
result = yield a # 先执行右边,会阻塞在这里
print('result>>', result)
a, b = b, a + b
con += 1
return 123
g = generator(5)
g.close() # 关闭生成器,后续的值将取不了
# send 方法可以启动生成器都是第一次传的值必须是空
print(next(g)) # 这也可以取出来
print(g.send('huran'))
for i in g: # 还可以用for循环
print(i, end='-')
# 捕获生成器的返回值
while True:
try:
ret = next(g)
print(ret)
except Exception as e:
print(e.value)
break
yield完成多任务
利用就是yield会阻塞的特性
import time
def task1():
while True:
print("--1--")
time.sleep(0.1)
yield
def task2():
while True:
print("--2--")
time.sleep(0.1)
yield
def main():
t1 = task1()
t2 = task2()
while True:
next(t1)
next(t2)
if __name__ == "__main__":
main()
yield from
chain()可传入多个可迭代的对象,对他们进行一个for循环取出值来。
lis = [1, 2, 3]
dis = {
'name': 'juran',
'age': 18
}
def my_chian(*args, **kwargs):
for val in args:
yield from val
for value in my_chian(lis, dis):
print(value)
yield from
def generator_1(): # 子生成器
total = 0
while True:
x = yield
print('加', x)
if not x:
break
total += x
return total
def generator_2(): # 委托生成器
while True:
total = yield from generator_1() # 子生成器
print('加和总数是:', total)
def main(): # 调用方
# g1 = generator_1()
# g1.send(None)
# g1.send(2)
# g1.send(3)
# g1.send(None)
g2 = generator_2()
g2.send(None)
g2.send(2)
g2.send(3)
g2.send(None)
if __name__ == '__main__':
main()
【子生成器】:yield from后的generator_1()生成器函数是子生成器
【委托生成器】:generator_2()是程序中的委托生成器,它负责委托子生成器完成具体任务。
【调用方】:main()是程序中的调用方,负责调用委托生成器。
协程
协程,又称微线程
协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)
Python中的协程大概经历了如下三个阶段:
- 最初的生成器变形yield/send
- yield from
- 在最近的Python3.5版本中引入async/await关键字
协程的实现
from greenlet import greenlet
import time
def greenlet_1():
while True:
print('--1--')
g2.switch()
time.sleep(0.5)
def greenlet_2():
while True:
print('--2--')
g1.switch()
time.sleep(0.5)
g1 = greenlet(greenlet_1)
g2 = greenlet(greenlet_2)
g1.switch()
gevent实现多任务
遇到等待会自动切换到另外一个任务
import gevent
from gevent import monkey
monkey.patch_all() # 将所用的噩耗时操作换为gevent模块的
def test1(n):
for i in range(n):
print(gevent.getcurrent(), i)
gevent.sleep(0.5) # 这里会有等待,会自动在上一步自动切换到另外一个
def test2():
while True:
print(gevent.getcurrent(), '---2---')
gevent.sleep(0.5) # 这里会有等待,会自动在上一步自动切换到另外一个
t1 = gevent.spawn(test1, 2) # 第一个参数是对象,第二个是参数(传入函数中的,可有可无)
t2 = gevent.spawn(test2)
t1.join() # 要等到执行完毕,否则直接到这里
t2.join()
案例:
import gevent
from gevent import monkey
monkey.patch_all()
import requests
def download(url):
print("get:%s" % url)
ret = requests.get(url)
data = ret.text
print(len(data), ret)
g1 = gevent.spawn(download, 'https://www.kancloud.cn/ju7ran/gaoji/1474878')
g2 = gevent.spawn(download, 'https://fanyi.baidu.com/?fr=websearch_submit&pid=sogou__free#pt/zh/%3CGreenlet')
g1.join()
g2.join()
访问的网站并不是按照你写的顺序来执行完成的,而是先执行完时间短一点的,
总结:
进程是资源分配的基本单位
线程是操作系统调度和执行的单位
进程切换需要的资源很最大,效率很低
线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
协程切换任务资源很小,效率高
多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中 所以是并发