天天看點

單線程+異步協程的操作

**協程是比線程更小的一種執行單元,你可以認為是輕量級的線程,之是以說輕,一方面是因為協程所持有的棧比線程要小很多,java會為每個線程配置設定1M左右的棧空間,而協程可能隻有幾十或者幾百K。

有些語言比如node.js,go在語言層面上支援了協程,而有些語言比如C需要使用第三方庫才可以擁有協程的能力。

協程是基于線程實作的,協程的建立、切換、銷毀都是在某個線程中來進行的。

使用協程是因為線程的切換成本比較高,而協程在這方面很有優勢。

**

event_loop:事件循環,相當于一個無線循環,我們可以吧一些函數注冊到這個事件循環上,當滿足某些條件的時候,函數就會被循環執行。

coroutine:協程對象。我們可以将協程對象注冊到事件循環中,它會被事件循環調用。我們可以使用async關鍵字來定義一個方法,這個方法在調用的時候不會立即被執行,而是傳回一個協程對象。

task:任務,它是對協程對象的進一步封裝,包含了任務的各個狀态。

future:代表将來執行或還沒有執行的任務,實際上和task沒有本質差別。

async:定義一個協程。

await:用來挂起阻塞方法的執行。

事件循環相應的操作

import asyncio

async def request(url):
    print('正在請求的url是',url)
    print('請求成功,',url)
    return url
#async修飾的函數,調用之後傳回的一個協程對象
#該函數如果被調用之後,函數内部的語句不會馬上被執行
c = request('www.baidu.com')

# #建立一個事件循環對象
loop = asyncio.get_event_loop()
# #将協程對象注冊到loop中,然後啟動loop
loop.run_until_complete(c)
#這一句既可以實作協程注冊,又可以實作啟動協程循環
           

我們首先使用回調函數進行操作

import asyncio

async def request(url):
    print('正在請求的url是',url)
    print('請求成功,',url)
    return url
#async修飾的函數,調用之後傳回的一個協程對象
#該函數如果被調用之後,函數内部的語句不會馬上被執行
c = request('www.baidu.com')

#future的使用
#loop = asyncio.get_event_loop()
#task = asyncio.ensure_future(c)
#print(task)
#loop.run_until_complete(task)
#print(task)

def  callback_func(task):
    print(task.result())
#回調函數

#綁定回調
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(c)
#現在已經将協程對象注冊到對應的任務之中
loop.run_until_complete(task)
           

此時操作的時候發現隻調用了request相應的函數,回調函數并沒有執行成功。還需要将回調函數綁定到任務對象中。

單個線程多個協程的相應的操作如下

import asyncio
import time

async def request(url):
    print('正在下載下傳',url)
    #在異步協程中如果出現了同步子產品相關的代碼,那麼就無法實作異步。
    # time.sleep(2),sleep為同步子產品的相關代碼
    #當在asyncio中遇到阻塞操作必須進行手動挂起,也就是前面的await參數
    await asyncio.sleep(2)
    print('下載下傳完畢',url)

start = time.time()
urls = [
    'www.baidu.com',
    'www.sogou.com',
    'www.goubanjia.com'
]

#任務清單:存放多個任務對象
stasks = []
for url in urls:
    c = request(url)
    #拿到了一個對應的協程對象
    task = asyncio.ensure_future(c)
    #将這一個協程對象封裝到對應的任務對象當中
    stasks.append(task)
    #将任務對象注冊到任務清單之中

loop = asyncio.get_event_loop()
#需要将任務清單封裝到wait中
loop.run_until_complete(asyncio.wait(stasks))
#将任務對象注冊到循環對象之中,注意這裡不能直接将stasks
#放置到run_until_complete參數之中
print(time.time()-start)