Python多任务 协程

1. 协程

1-1. 同步、异步

同步: 指代码调用IO操作时,必须等待IO操作完成才返回的调用方式
异步: 指代码调用IO操作时,不必等IO操作完成就返回的调用方式

1-2. 阻塞与非阻塞

阻塞: 从调用者的角度出发,如果在调用的时候,被卡住,不能再继续向下运行,需要等待,就说是阻塞
非阻塞: 从调用者的角度出发, 如果在调用的时候,没有被卡住,能够继续向下运行,无需等待,就说是非阻塞

1-3. 生成器-send方法

定义: send方法有一个参数,该参数指定的是上一次被挂起的yield语句的返回值

1-4. 使用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()

1-5. 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()是程序中的调用方,负责调用委托生成器。

1-6.如何使用协程

定义:

  • 协程,又称微线程。
  • 协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)

协程的三个阶段:

  1. 最初的生成器变形 yield/send
  2. yield from
  3. 在最近的Python3.5版本中引入async/await关键字

1-7. 使用greenlet完成多任务

案例参考:

from greenlet import greenlet
import time

# 协程利用IO 来切换任务
def demo1():
	while True:
		print("demo1")
		gr2.switch()	# 开始

def demo2():
	while True:
		print("demo2")
		gr1.switch()	# 开始

gr1 = greenlet(demo1)	# 创建
gr2 = greenlet(demo2)	# 创建

gr1.switch()	# 开始

1-8. 使用gevent完成多任务

案例参考:

import gevent
import time
from gevent import monkey
# 将程序中用到的耗时操作, 换位gevent中实现的莫块
monkey.patch_all()

def f1(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        time.sleep(0.5)
        # gevent.sleep(0.5)

def f2(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        time.sleep(0.5)
        # gevent.sleep(0.5)

def f3(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        time.sleep(0.5)
        # gevent.sleep(0.5)

print("--1--")
g1 = gevent.spawn(f1, 5)
print("--2--")
time.sleep(1)
# gevent.sleep(0.5)
g2 = gevent.spawn(f2, 5)
print("--3--")
g3 = gevent.spawn(f3, 5)
print("--4--")


g1.join()
g2.join()
g3.join()

tips:
from gevent import monkey
将程序中用到的耗时操作, 换位gevent中实现的模块
monkey.patch_all()

总结:

  • 进程是资源分配的单位
  • 线程是操作系统调度的单位
  • 进程切换需要的资源很最大,效率很低
  • 线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
  • 协程切换任务资源很小,效率高
  • 多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中 所以是并发
发布了27 篇原创文章 · 获赞 11 · 访问量 1481

猜你喜欢

转载自blog.csdn.net/weixin_45550881/article/details/104032281