1.关于协程
线程和进程都是系统帮咱们开辟的,不管是thread还是process他内部都是调用的系统的API,而对于协程来说它和系统毫无关系;
协程不同于线程的是,线程是抢占式的调度,而协程是协同式的调度,也就是说,协程需要自己做调度。
优点:
无需线程上下文切换的开销,协程避免了无意义的调度,由此可以提高性能
无需原子操作锁定及同步的开销
方便切换控制流,简化编程模型
高并发+高扩展性+低成本
2.实现协程
yield实现协程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23def consumer(name):
print("要开始啃骨头了...")
while True:
print("\033[31;1m[consumer] %s\033[0m " % name)
bone = yield
print("[%s] 正在啃骨头 %s" % (name, bone))
def producer(obj1, obj2):
obj1.send(None) //启动obj1这个生成器,第一次必须用None <==> obj1.__next__()
obj2.send(None) //启动obj2这个生成器,第一次必须用None <==> obj2.__next__()
n = 0
while n < 5:
n += 1
print("\033[32;1m[producer]\033[0m 正在生产骨头 %s" % n)
obj1.send(n)
obj2.send(n)
if __name__ == '__main__':
con1 = consumer("消费者A")
con2 = consumer("消费者B")
producer(con1, con2)greenlet实现协程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#! /usr/bin/env python
# -*- coding:utf-8 -*-
from greenlet import greenlet
# greenlet 其实就是手动切换;gevent是对greenlet的封装,可以实现自动切换
def test1():
print("123")
gr2.switch() # 切换去执行test2
print("456")
gr2.switch() # 切换回test2之前执行到的位置,接着执行
def test2():
print("789")
gr1.switch() # 切换回test1之前执行到的位置,接着执行
print("666")
gr1 = greenlet(test1) # 启动一个协程 注意test1不要加()
gr2 = greenlet(test2) #
gr1.switch()gevent 实现协程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21import gevent
def func1():
print("func1 running")
gevent.sleep(2) # 内部函数实现io操作
print("switch func1")
def func2():
print("func2 running")
gevent.sleep(1)
print("switch func2")
def func3():
print("func3 running")
gevent.sleep(0)
print("func3 done..")
gevent.joinall([gevent.spawn(func1),
gevent.spawn(func2),
gevent.spawn(func3),
])