Python學習之路-隨筆03 多線程/進程和協程(下篇)

下面屬於協程的應用和以前剩下的沒寫詳細的。html

asyncio

上篇說過了協程之間切換的開銷極小,用這個相對於threading的優點以及業務場景對比還有各類細分的對比能扯不少,我以爲在我目前的階段不須要太糾結這個python

即把這個當成threading的替代便可,asyncio能夠簡單認爲比threading併發量更大,內存開銷更小就好了(GIL平常先背個鍋)服務器

再說說簡單的用法,首先asyncio是一個消息循環,有什麼用呢?首先說一下協程工做完一段代碼以後要返回主線程,可是這時候可能主線程也在忙,而asyncio至關於併發

一個信箱,FIFO樣式的,協程工做完就把完成通知丟到「信箱」裏面去,供主線程有空的時候順序讀取以便安排新的任務。框架

看代碼:async

 1 import threading
 2 import asyncio
 3 
 4 @asyncio.coroutine
 5 def t1():
 6     print('去洗菜', threading.currentThread())
 7     yield from asyncio.sleep(5)
 8     print('炒菜', threading.currentThread())
 9     
10 @asyncio.coroutine
11 def t2():
12     print('洗米', threading.currentThread())
13     yield from asyncio.sleep(5)
14     print('煮飯', threading.currentThread())
15 
16 @asyncio.coroutine
17 def t3():
18     print('洗衣服', threading.currentThread())
19     yield from asyncio.sleep(5)
20     print('晾衣服', threading.currentThread())
21     
22 loop = asyncio.get_event_loop()
23 tasks = [t1(),t2(),t3()]
24 loop.run_until_complete(asyncio.wait(tasks))
25 loop.close()
out:  去洗菜 <_MainThread(MainThread, started 7732)>
      洗米 <_MainThread(MainThread, started 7732)>
      洗衣服 <_MainThread(MainThread, started 7732)>
      炒菜 <_MainThread(MainThread, started 7732)>
      煮飯 <_MainThread(MainThread, started 7732)>
      晾衣服 <_MainThread(MainThread, started 7732)>

@asyncio.coroutine 表面這是一個要扔到消息循環(loop)的協程。asyncio.get_event_loop()是建立一個消息循環,而後分配任務,執行任務並等待任務結束,關閉消息循環。這就是一個簡單的用法。ide

而後爲了簡化@asyncio.coroutine和yield from,從python3.5開始引入了async and await,使用方法就是用async替換掉@asyncio.coroutine,await替換掉yield from函數

async def t1():
    print('去洗菜', threading.currentThread())
    await asyncio.sleep(5)
    print('炒菜', threading.currentThread())

而後還有諸如綁定回調,協程嵌套等等其餘用法暫時參考http://www.javashuo.com/article/p-okfxrbuu-c.html,否則就等我後面的更新哈哈哈哈哈哈<( ̄︶ ̄)↗ oop

aiohttp

爲何寫這玩意兒呢,我隱隱以爲之後會用到它,因此先記下來。spa

這玩意兒是基於asyncio(就是上面那玩意兒)實現的HTTP框架,能夠實現單線程併發IO,主要用於服務器端。畢竟HTTP做爲一個IO操做開銷也是很大的呀

用以前就先得裝好pip install aiohttp或者在ananconda裏面點一點安裝

真的只是先記下來啊,待我之後再來一篇(¬_¬)

concurrent.futures

一個相似於其餘語言的線程池的概念,用的是multiprocessing,真正的並行計算。上面的協程只是僞並行計算。

首先要用到的東西concurrent.futures.Executor,裏面有兩個

ThreadPoolExecutor和ProcessPoolExecutor,建池子的時候要指定用哪一個,而後給裏面的max_workers這個參數安排一下數量,給幾個核幹活。

而後用submit提交任務和任務參數,submit(fn, args, kwargs),而後done執行,result獲取結果。

 1 from concurrent.futures import ThreadPoolExecutor
 2 import time
 3 
 4 
 5 def task(msg):
 6     time.sleep(5)
 7     return msg
 8 
 9 
10 # 建立一個線程池
11 pool = ThreadPoolExecutor(max_workers=2)
12 
13 # 往線程池加入2個task
14 t1 = pool.submit(task, 'hello')
15 t2 = pool.submit(task, 'world')
16 
17 print(t1.done())
18 time.sleep(5)
19 print(t2.done())
20 
21 print(t1.result())
22 print(t2.result())
View Code

而後還有一個判斷任務是否結束的問題,能夠用as_completed這個方法來實現(用以前要導入= =)

for future in as_completed(all_task):
    data = future.result()

大概這樣用

還有一個map函數,好比給同一個任務分配不一樣的參數丟進線程池執行

args = ['hello', 'world']
for data in pool.map(task, args):
    print(data)

這樣用呢省去了submit的步驟,而後有一個就是最後的輸出順序是按照參數的順序來的,而不是執行完成的順序。

暫停一下。未完待續

相關文章
相關標籤/搜索