单线程并发——协程

1. 什么是协程

协程,英文名称为 Coroutine,经常被称为微线程,纤程,是一种多任务并发的操作手段
PYTHON 中的多任务处理,根据资源消耗情况可以选择多进程并发、多线程并发,同时也可
以在节省系统资源的情况下选择协程并发,协程由于是工作在一个线程中的执行单元,所以
系统资源消耗是最少的

定义:协程是运行在单线程中的并发程序!

由于协程省去了多线程、多进程并发机制下的切换管理和状态数据管理等,所以操作效率较
高,PYTHON 不同的版本中提供了不少关于协程的支持,我们从最简单的多任务并发逐步深
入了解 PYTHON 中的协程

2.python中gevent模块下多任务操作协程

协程既然是多任务并发,肯定是参考了多线程的工作机制,我们安装 gevent 模块完成最基
本的多任务操作协程
pip install gevent

3 协程:多任务手工切换

我们回到最初的多任务并发,要求在程序中一边唱歌一边跳舞的功能实现

import time
from greenlet import greenlet


def sing():
    # 定义唱歌的函数
    while True:
        print("唱歌》》》")
        time.sleep(1)
        # 切换运行协程2
        g2.switch()


def dance():
    while True:
        print("跳舞》》》》")
        time.sleep(1)
        # 切换运行协程1
        g1.switch()


if __name__ == "__main__":
    # 创建两个协程对象
    g1 = greenlet(sing)
    g2 = greenlet(dance)
    # 切换到协程1工作
    g1.switch()

    print("主进程执行...")

4 协程:多任务自动切换

我们通过事件操作模块gevent,让多个任务根据自己的运行状态进行自动切换

import gevent
import threading


def sing():
    # 定义唱歌函数
    while True:
        print("唱歌>>>", threading.current_thread().getName())
        # 事件休眠,让出执行时间片
        gevent.sleep(1)


def dance():
    # 定义跳舞函数
    while True:
        print("跳舞>>>", threading.current_thread().getName())
        # 事件休眠,让出时间片
        gevent.sleep(3)


if __name__ == "__main__":
    # 常见跳舞、唱歌的协程
    s = gevent.spawn(sing)
    d = gevent.spawn(dance)
    # 独占时间片运行
    s.join()
    d.join()

执行代码运行程序,可以看到他们是工作在一个线程中的执行单元

5 协程:基于python生成器对象的多任务

Python 中为了有效的利用内存进行程序的运算操作,提供了一个生成器对象 yield
所谓生成器,就是在程序运行执行到该代码时才参与运算得到结果,经常被用作协程操作和
组合数据类型的推导生成
由于其执行即运算的特性,通过生成器操作也可以完成协程的处理

import time


def sing():
    while True:
        time.sleep(1)
        print("唱歌》》》")
        yield
        
        
def dance():
    while True:
        time.sleep(1)
        print("跳舞>>>")
        next(s)
        

if __name__ == "__main__":
    s = sing()
    d = dance()

生成器对象主要的核心函数就是next(),通过next()方法才能执行运算得到运算的下一个结果值,所以这里有效的利用yield完成了一次协程的工作。但是毕竟yield错做协程的可读性较差。

6 协程:python3.4+版本

PYTHON3.4 版本中添加了异步 io 操作模块 asyncio,对于协程的操作支持就变得比较友好
了,通过异步 io 操作,可以将多路 io 程序通过协程的方式提升操作效率

import asyncio


# 添加一个注解,标注这个函数是一个协程函数
@asyncio.coroutine
def show_info(name):
    for i in range(0, 10):
        print(name, "输出数据>>>")
        # 异步执行代码,模拟耗时2s
        yield from asyncio.sleep(2)


if __name__ == "__main__":
    # 获取异步IO时间轮询对象
    loop = asyncio.get_event_loop()
    # 编译执行
    loop.run_until_complete(asyncio.gather(show_info("tom"), show_info("jerry")))
    # 关闭时间 轮询
    loop.close()

前面那个唱歌跳舞的异步IO协程改版

import asyncio


@asyncio.coroutine
def sing():
    while True:
        print("唱歌》》》")
        yield from asyncio.sleep(2)


@asyncio.coroutine
def dance():
    while True:
        print("跳舞》》》")
        yield from asyncio.sleep(2)


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.gather(sing(), dance()))
    loop.close()

7 python3.5版本

PYTHON3.5 又增加了新的操作机制以提高对协程的支持
新增 async 替代了原来的@asyncio.corotine,新增 await 替代了原有的 yield from 步骤,简
化和优化了原有协程处理流程,这一部分异步操作,在以后的各个需要异步操作的方面都有
着非常广泛的应用。

import asyncio


async def sing():
    while True:
        print("唱歌》》》")
        # 异步操作
        await asyncio.sleep(2)


async def dance():
    while True:
        print("不如跳舞》》》")
        await asyncio.sleep(1)


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.gather(sing(), dance()))
    loop.close()

猜你喜欢

转载自www.cnblogs.com/chenliang0309/p/9782902.html