python3 - 协程

目录

协程(Coroutine):单线程实现并发的概念

- 单线程下,未加入协程概念的任务执行(串行)

 - 单线程下,基于yield并发执行

- gevent 模块:第三方库,实现同步并发或异步编程。


协程(Coroutine):单线程实现并发的概念

由于并发的概念,即在同段时间内同时执行任务,核心在于切换执行和保存执行状态。所以,只要在单线程中实现‘任务切换’+‘保存执行状态’就能实现所谓的并发。

优点:协程即在单线程下实现多个任务遇到I/O切换,降低单线程的IO时间,最大限度的提升单线程的效率。

注:协程的概念不存在于操作系统之中,只是单线程下实现并发的概念名,非正统。

协程 VS 操作系统

  优点:

  1. 协程的切换开销更小,属于程序级别的切换,不涉及操作系统,更加轻量级
  2. 单线程内实现并发的效果,最大限度的利用cpu

  缺点:

  1.   协程的本质是单线程下,无法利用多核。即,一个程序下开启多进程,单进程下开启多线程,单线程下开启协程。
  2.   协程一旦出现阻塞,会阻塞整个线程。

总结:

  1. 只能在单线程下实现
  2. 修改共享数据不需要加锁
  3. 程序内保存多个控制流的上下文栈
  4. 使用gevent实现 IO 切换协程

- 单线程下,未加入协程概念的任务执行(串行)

# 串行执行
import time


def func1():
    for i in range(10000000):
        i + 1


def func2():
    for i in range(10000000):
        i + 1


start = time.time()
func1()
func2()
stop = time.time()
print(stop - start)

'''
1.2944164276123047
'''

 - 单线程下,基于yield并发执行

使用yield原因: yiled可以保存状态,即运行到yiled进行暂停,等待next操作。相对于系统操作的保存状态,yield作为代码级别,更加轻量

缺点:只能单一切换执行,不存在判断各类型 I/O 操作,降低程序的效率

'''基于yield并发执行:无法判断是否为IO操作,单一性执行的切换'''
import time


def func1():
    while True:
        print('func1')
        10000000 + 1
        yield


def func2():
    g = func1()
    for i in range(100):
        print('func2')
        time.sleep(5)
        i + 1
        next(g)


start = time.time()
func2()
stop = time.time()
print(stop - start)

'''
func2
func1
func2
func1
func2
func1
func2
……
'''

- gevent 模块:第三方库,实现同步并发或异步编程。

gevent模块是一个第三方库,可用于实现识别协程内部IO操作,进行协程间的切换操作。

注:使用gevent模块,并向对IO操作进行识别切换时候,必须添加 “前置打包操作(补丁)”

      即:from gevent import monkey;monkey.patch_all()      加入‘;’可同行写入

用法:

spawn 组件: gobj = gevent.spawn( func,1,3,4,x=4,) 创建协程对象gobj,spawn(任务函数名,函数的位置参数/关键字参数)

gobj.join() :主线程等待gobj结束,因为是异步提交,如果不作此行为,提交结束后直接往下执行。

gobj.value() : 拿到任务函数的返回值

# '''gevent 实现协程概念'''
from gevent import monkey;monkey.patch_all()
from gevent import spawn, joinall  # pip3 install gevent
import time


def play(name):
    print('%s play 1' % name)
    time.sleep(5)
    print('%s play 2' % name)


def eat(name):
    print('%s eat 1' % name)
    time.sleep(3)
    print('%s eat 2' % name)


start = time.time()
# 异步提交
g1 = spawn(play, 'who')
g2 = spawn(eat, 'who')

# g1.join()
# g2.join()

# 等同于前两步
joinall([g1, g2])
print('主', time.time() - start)

'''
who play 1
who eat 1
who eat 2
who play 2
主 5.005553483963013
'''

猜你喜欢

转载自blog.csdn.net/qq_33961117/article/details/82594198