單線程併發——協程

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()
相關文章
相關標籤/搜索