单线程并发——协程

1. 什么是协程

协程,英文名称为 Coroutine,常常被称为微线程,纤程,是一种多任务并发的操做手段
PYTHON 中的多任务处理,根据资源消耗状况能够选择多进程并发、多线程并发,同时也可
以在节省系统资源的状况下选择协程并发,协程因为是工做在一个线程中的执行单元,因此
系统资源消耗是最少的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,让多个任务根据本身的运行状态进行自动切换async

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
所谓生成器,就是在程序运行执行到该代码时才参与运算获得结果,常常被用做协程操做和
组合数据类型的推导生成
因为其执行即运算的特性,经过生成器操做也能够完成协程的处理oop

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 程序经过协程的方式提高操做效率spa

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()
相关文章
相关标签/搜索