py并发_多协程笔记

多协程

python是为数不多支持多协程开发编程语言,协程(微线程、纤程)是一种比线程要小的控制单元,其本身不受到操作系统环境的控制,全部都由开发者来进行控制,不管是进程还是线程实际上都会受到各种轮转处理的操作问题,例如:执行了一段时间之后一定要让出资源,交由其它进程或者是线程进行处理,这样的处理过程之中就一定会造成许多不必要的性能开支。

进程线程协程

程序级实现

协程(Coroutine)即协作式程序,又可以称为“微线程” 或“纤程”,所有的协程是通过线程创建的,协程与进程或线程最大的区别就是进程与线程为系统级实现,而协程为程序级实现

比较

前景

在python提供的并发编程实现之中,多协程的开发是性能最高的一种实现形式,未来实际上Python也会在多协程上进行各种发力(未来的时代也一定会逐步地迈入到协程的时代)

测试

yield实现多协程

在python中协程主要是通过程序来实现的控制,而对于协程的控制可以直接使用Python提供的yield关键字来完成,利用一些局部返回的处理操作,就可以实现多个协程的处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# coding: UTF-8
def producer(cons): # 生产者
info = None # 生产数据
cons.send(info) # 必须首先发送一个None数据
for item in range(10):
if item % 2 == 0:
info = "title = 你好、content = 你不停穿梭在城市里"
else:
info = "title = 哈喽、content = 也有无数人等着你"
print("[生产者]%s" % info)
cons.send(info) # 将数据发送给消费者
def consumer(): # 消费者
while True: # 不断进行消费处理
receive = yield # 等待进行数据的接收
print("【消费者】%s" % receive) # 消费者输出信息
def main():
con = consumer() # 定义消费者
producer(con)
if __name__ == "__main__":
main()

[生产者]title = 你好、content = 你不停穿梭在城市里
【消费者】title = 你好、content = 你不停穿梭在城市里
[生产者]title = 哈喽、content = 也有无数人等着你
【消费者】title = 哈喽、content = 也有无数人等着你
[生产者]title = 你好、content = 你不停穿梭在城市里
【消费者】title = 你好、content = 你不停穿梭在城市里
[生产者]title = 哈喽、content = 也有无数人等着你
【消费者】title = 哈喽、content = 也有无数人等着你
[生产者]title = 你好、content = 你不停穿梭在城市里
【消费者】title = 你好、content = 你不停穿梭在城市里
[生产者]title = 哈喽、content = 也有无数人等着你
【消费者】title = 哈喽、content = 也有无数人等着你
[生产者]title = 你好、content = 你不停穿梭在城市里
【消费者】title = 你好、content = 你不停穿梭在城市里
[生产者]title = 哈喽、content = 也有无数人等着你
【消费者】title = 哈喽、content = 也有无数人等着你
[生产者]title = 你好、content = 你不停穿梭在城市里
【消费者】title = 你好、content = 你不停穿梭在城市里
[生产者]title = 哈喽、content = 也有无数人等着你
【消费者】title = 哈喽、content = 也有无数人等着你

进程已结束,退出代码0

greenlet实现多协程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# coding :UTF-8
import greenlet,time
info = None # 保存要生产的数据
def producer_handle(): # 生产者
global info # 使用全局变量
for item in range(10):
if item % 2 == 0:
info = "title = 你好、content = 雪山的那一边会是怎么样"
else:
info = "title = 哈喽、content = 那里是牧场还是天堂"
print("[生产者]%s" % info)
time.sleep(1) # 延迟
consumer_greenlet.switch() # 切换到消费端
def consumer_handle(): # 消费者
while True:
print("【消费者】%s" % info) # 获取信息
time.sleep(1) # 延迟
producer_greenlet.switch() # 切换到生产端
producer_greenlet = greenlet.greenlet(run=producer_handle) # 定义协程切换函数
consumer_greenlet = greenlet.greenlet(run=consumer_handle) # 定义协程切换函数
def main(): # 主函数
producer_greenlet.switch() # 生产者现在需要首先执行
if __name__ == "__main__": # 判断程序执行名称
main()

[生产者]title = 你好、content = 雪山的那一边会是怎么样
【消费者】title = 你好、content = 雪山的那一边会是怎么样
[生产者]title = 哈喽、content = 那里是牧场还是天堂
【消费者】title = 哈喽、content = 那里是牧场还是天堂
[生产者]title = 你好、content = 雪山的那一边会是怎么样
【消费者】title = 你好、content = 雪山的那一边会是怎么样
[生产者]title = 哈喽、content = 那里是牧场还是天堂
【消费者】title = 哈喽、content = 那里是牧场还是天堂
[生产者]title = 你好、content = 雪山的那一边会是怎么样
【消费者】title = 你好、content = 雪山的那一边会是怎么样
[生产者]title = 哈喽、content = 那里是牧场还是天堂
【消费者】title = 哈喽、content = 那里是牧场还是天堂
[生产者]title = 你好、content = 雪山的那一边会是怎么样
【消费者】title = 你好、content = 雪山的那一边会是怎么样
[生产者]title = 哈喽、content = 那里是牧场还是天堂
【消费者】title = 哈喽、content = 那里是牧场还是天堂
[生产者]title = 你好、content = 雪山的那一边会是怎么样
【消费者】title = 你好、content = 雪山的那一边会是怎么样
[生产者]title = 哈喽、content = 那里是牧场还是天堂
【消费者】title = 哈喽、content = 那里是牧场还是天堂

进程已结束,退出代码0

在整个的程序的协程切换过程之中,完全不再去关注yield以及send()函数的使用了,全部都使用greenlet进行了相关的处理包装,而这样的处理操作可以极大的简化内置的协程开发操作。

gevent简化协程开发

为了进一步简化协程的开发,在python中又提供了一个gevent第三方模块,使用greenlet进行协程操作的时候需要开发者手工进行切换处理,但是gevent可以实现自动的切换,这种自动切换一般都是需要设置一些触发条件的,例如:为了防止程序的执行过快在greenlet中可能追加延迟操作,而后再进行手工的switch()调用,但是如果使用gevent模块,里面直接提供有一个sleep()函数,这样在休眠的时候可以自动地延迟切换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# coding : UTF-8
import gevent
info = None # 保存要生产的数据
def producer_handle(): # 生产者
global info # 使用全局变量
for item in range(10):
if item % 2 == 0:
info = "title = 你好、content = 天微微亮有谁在你身旁"
else:
info = "title = 哈喽、content = 你说你要牵我的手去流浪"
print("[生产者]%s" % info)
gevent.sleep(1) # 延迟切换
def consumer_handle(): # 消费者
while True:
print("【消费者】%s" % info) # 获取信息
gevent.sleep(1) # 延迟切换
def main():
producer_gevent = gevent.spawn(producer_handle)
consumer_gevent = gevent.spawn(consumer_handle)
producer_gevent.join() # 协程启动
consumer_gevent.join() # 协程启动
if __name__ == "__main__":
main()

[生产者]title = 你好、content = 天微微亮有谁在你身旁
【消费者】title = 你好、content = 天微微亮有谁在你身旁
[生产者]title = 哈喽、content = 你说你要牵我的手去流浪
【消费者】title = 哈喽、content = 你说你要牵我的手去流浪
[生产者]title = 你好、content = 天微微亮有谁在你身旁
【消费者】title = 你好、content = 天微微亮有谁在你身旁
[生产者]title = 哈喽、content = 你说你要牵我的手去流浪
【消费者】title = 哈喽、content = 你说你要牵我的手去流浪
[生产者]title = 你好、content = 天微微亮有谁在你身旁
【消费者】title = 你好、content = 天微微亮有谁在你身旁
[生产者]title = 哈喽、content = 你说你要牵我的手去流浪
【消费者】title = 哈喽、content = 你说你要牵我的手去流浪
[生产者]title = 你好、content = 天微微亮有谁在你身旁
【消费者】title = 你好、content = 天微微亮有谁在你身旁
[生产者]title = 哈喽、content = 你说你要牵我的手去流浪
【消费者】title = 哈喽、content = 你说你要牵我的手去流浪
[生产者]title = 你好、content = 天微微亮有谁在你身旁
【消费者】title = 你好、content = 天微微亮有谁在你身旁
[生产者]title = 哈喽、content = 你说你要牵我的手去流浪
【消费者】title = 哈喽、content = 你说你要牵我的手去流浪
【消费者】title = 哈喽、content = 你说你要牵我的手去流浪

……


py并发_多协程笔记
https://blog.wangxk.cc/2020/02/03/py并发-多协程笔记/
作者
Mike
发布于
2020年2月3日
许可协议