协程,又称微线程
协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)
通俗的理解:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定
协程和线程差异:
- # -*- coding: utf-8 -*-
- import time
-
-
- def work1():
- while True:
- print("----work1---")
- yield
- time.sleep(0.5)
-
-
- def work2():
- while True:
- print("----work2---")
- yield
- time.sleep(0.5)
-
-
- def main():
- w1 = work1()
- w2 = work2()
- while True:
- next(w1)
- next(w2)
-
-
- if __name__ == "__main__":
- main()
-
- """
- ----work1---
- ----work2---
- ----work1---
- ----work2---
- ----work1---
- ----work2---
- ...
- """
使用pip install安装greenlet模块: pip install greenlet
- # -*- coding: utf-8 -*-
- from greenlet import greenlet
- import time
-
-
- def test1():
- while True:
- print("---A--")
- gr2.switch()
- time.sleep(0.5)
-
-
- def test2():
- while True:
- print("---B--")
- gr1.switch()
- time.sleep(0.5)
-
-
- gr1 = greenlet(test1)
- gr2 = greenlet(test2)
-
- # 切换到gr1中运行
- gr1.switch()
-
-
- """
- ---A--
- ---B--
- ---A--
- ---B--
- ---A--
- ---B--
- ...
- """
gevent比greenlet更强大,并且能够自动切换任务的模块
其原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。
由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO
安装: pip3 install gevent
- # -*- coding: utf-8 -*-
-
- import gevent
-
- def f(n):
- for i in range(n):
- print(gevent.getcurrent(), i)
-
- g1 = gevent.spawn(f, 5)
- g2 = gevent.spawn(f, 5)
- g3 = gevent.spawn(f, 5)
- g1.join()
- g2.join()
- g3.join()
-
- """
- <Greenlet "Greenlet-0" at 0x15233e9c378: f(5)> 0
- <Greenlet "Greenlet-0" at 0x15233e9c378: f(5)> 1
- <Greenlet "Greenlet-0" at 0x15233e9c378: f(5)> 2
- <Greenlet "Greenlet-0" at 0x15233e9c378: f(5)> 3
- <Greenlet "Greenlet-0" at 0x15233e9c378: f(5)> 4
- <Greenlet "Greenlet-1" at 0x15233e9c488: f(5)> 0
- <Greenlet "Greenlet-1" at 0x15233e9c488: f(5)> 1
- <Greenlet "Greenlet-1" at 0x15233e9c488: f(5)> 2
- <Greenlet "Greenlet-1" at 0x15233e9c488: f(5)> 3
- <Greenlet "Greenlet-1" at 0x15233e9c488: f(5)> 4
- <Greenlet "Greenlet-2" at 0x15233e9c598: f(5)> 0
- <Greenlet "Greenlet-2" at 0x15233e9c598: f(5)> 1
- <Greenlet "Greenlet-2" at 0x15233e9c598: f(5)> 2
- <Greenlet "Greenlet-2" at 0x15233e9c598: f(5)> 3
- <Greenlet "Greenlet-2" at 0x15233e9c598: f(5)> 4
- """
可以看到,3个greenlet是依次运行而不是交替运行
- # -*- coding: utf-8 -*-
- import gevent
-
-
- def f(n):
- for i in range(n):
- print(gevent.getcurrent(), i)
- # 用来模拟一个耗时操作,注意不是time模块中的sleep
- gevent.sleep(1)
-
-
- g1 = gevent.spawn(f, 5)
- g2 = gevent.spawn(f, 5)
- g3 = gevent.spawn(f, 5)
- g1.join()
- g2.join()
- g3.join()
-
-
- """
- <Greenlet "Greenlet-0" at 0x28fa86cc488: f(5)> 0
- <Greenlet "Greenlet-1" at 0x28fa86cc378: f(5)> 0
- <Greenlet "Greenlet-2" at 0x28fa86cc598: f(5)> 0
- <Greenlet "Greenlet-0" at 0x28fa86cc488: f(5)> 1
- <Greenlet "Greenlet-1" at 0x28fa86cc378: f(5)> 1
- <Greenlet "Greenlet-2" at 0x28fa86cc598: f(5)> 1
- <Greenlet "Greenlet-0" at 0x28fa86cc488: f(5)> 2
- <Greenlet "Greenlet-1" at 0x28fa86cc378: f(5)> 2
- <Greenlet "Greenlet-2" at 0x28fa86cc598: f(5)> 2
- <Greenlet "Greenlet-0" at 0x28fa86cc488: f(5)> 3
- <Greenlet "Greenlet-1" at 0x28fa86cc378: f(5)> 3
- <Greenlet "Greenlet-2" at 0x28fa86cc598: f(5)> 3
- <Greenlet "Greenlet-0" at 0x28fa86cc488: f(5)> 4
- <Greenlet "Greenlet-1" at 0x28fa86cc378: f(5)> 4
- <Greenlet "Greenlet-2" at 0x28fa86cc598: f(5)> 4
- """
- # -*- coding: utf-8 -*-
- from gevent import monkey
- import gevent
- import random
- import time
-
-
- def coroutine_work(coroutine_name):
- for i in range(10):
- print(coroutine_name, i)
- time.sleep(random.random())
-
-
- gevent.joinall([
- gevent.spawn(coroutine_work, "work1"),
- gevent.spawn(coroutine_work, "work2")
- ])
-
- """
- work1 0
- work1 1
- work1 2
- work1 3
- work1 4
- work1 5
- work1 6
- work1 7
- work1 8
- work1 9
- work2 0
- work2 1
- work2 2
- work2 3
- work2 4
- work2 5
- work2 6
- work2 7
- work2 8
- work2 9
- """
- # -*- coding: utf-8 -*-
- from gevent import monkey
- import gevent
- import random
- import time
-
- # 有耗时操作时需要
- monkey.patch_all() # 将程序中用到的耗时操作的代码,换为gevent中自己实现的模块
-
-
- def coroutine_work(coroutine_name):
- for i in range(10):
- print(coroutine_name, i)
- time.sleep(random.random())
-
-
- gevent.joinall([
- gevent.spawn(coroutine_work, "work1"),
- gevent.spawn(coroutine_work, "work2")
- ])
-
- """
- work1 0
- work2 0
- work2 1
- work2 2
- work2 3
- work1 1
- work2 4
- work1 2
- work2 5
- work2 6
- work1 3
- work2 7
- work1 4
- work2 8
- work1 5
- work2 9
- work1 6
- work1 7
- work1 8
- work1 9
- """