1. 程式人生 > >Python異步IO

Python異步IO

當前 在線 處理 match 資料 start 應用程序 lose 封裝

在IO操作的過程中,當前線程被掛起,而其他需要CPU執行的代碼就無法被當前線程執行了。
我們可以使用多線程或者多進程來並發執行代碼,為多個用戶服務。
但是,一旦線程數量過多,CPU的時間就花在線程切換上了,真正運行代碼的時間就少了,結果導致性能嚴重下降。
異步IO:當代碼需要執行一個耗時的IO操作時,它只發出IO指令,並不等待IO結果,然後就去執行其他代碼了。一段時間後,當IO返回結果時,再通知CPU進行處理。
對於大多數IO密集型的應用程序,使用異步IO將大大提升系統的多任務處理能力。

1. 異步IO

1.1 協程

協程,又稱微線程,纖程。英文名Coroutine
子程序(函數)調用是通過棧實現的,一個線程就是執行一個子程序。

協程的執行過程中,在子程序內部可中斷,然後轉而去執行別的子程序,在適當的時候再回來接著執行。
Python對協程的支持是通過生成器實現的。
在生成器中,我們不但可以通過for循環來叠代,還可以不斷調用next()函數獲取由yield語句返回的下一個值。但是Pythonyield不但可以返回一個值,它還可以接收調用者發出的參數。

def consumer():
    r = ''
    while True:
        n = yield r
        if not n:
            return
        print('[CONSUMER] Consuming %s...' % n)
        r = '200 OK'

def produce(c):
    c.send(None)
    n = 0
    while n < 5:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)
        print('[PRODUCER] Consumer return: %s' % r)
    c.close()

c = consumer()
produce(c)
[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 4...
[CONSUMER] Consuming 4...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 5...
[CONSUMER] Consuming 5...
[PRODUCER] Consumer return: 200 OK

1.2 asyncio

asyncio的編程模型是一個消息循環。我們從asyncio模塊中直接獲取一個EventLoop的引用,然後把需要執行的協程扔到EventLoop中執行,就實現了異步IO。

import asyncio

@asyncio.coroutine
def hello():
    print("Hello world!")
    # 異步調用asyncio.sleep(1):
    r = yield from asyncio.sleep(1)
    print("Hello again!")

# 獲取EventLoop:
loop = asyncio.get_event_loop()
# 執行coroutine
loop.run_until_complete(hello())
loop.close()

@asyncio.coroutine把一個生成器標記為協程類型,然後,我們就把這個協程扔到EventLoop中執行。

import threading
import asyncio

@asyncio.coroutine
def hello():
    print('Hello world! (%s)' % threading.currentThread())
    yield from asyncio.sleep(1)
    print('Hello again! (%s)' % threading.currentThread())

loop = asyncio.get_event_loop()
tasks = [hello(), hello()] # 封裝兩個協程
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

# Hello world! (<_MainThread(MainThread, started 9700)>)
# Hello world! (<_MainThread(MainThread, started 9700)>)
# Hello again! (<_MainThread(MainThread, started 9700)>)
# Hello again! (<_MainThread(MainThread, started 9700)>)

1.3 async/await

import asyncio

async def hello():
    print("Hello world!")
    r = await asyncio.sleep(1)
    print("Hello again!")
    
    
# 獲取EventLoop:
loop = asyncio.get_event_loop()
# 執行coroutine
loop.run_until_complete(hello())
loop.close()

1.4 aiohttp

import asyncio

from aiohttp import web

async def index(request):
    await asyncio.sleep(0.5)
    return web.Response(body='<h1>Index</h1>'.encode('utf-8'), content_type='text/html')

async def hello(request):
    await asyncio.sleep(0.5)
    text = '<h1>hello, %s!</h1>' % request.match_info['name']
    return web.Response(body=text.encode('utf-8'), content_type='text/html')

async def init(loop):
    app = web.Application(loop=loop)
    app.router.add_route('GET', '/', index)
    app.router.add_route('GET', '/hello/{name}', hello)
    srv = await loop.create_server(app.make_handler(), '127.0.0.1', 8000)
    print('Server started at http://127.0.0.1:8000...')
    return srv

loop = asyncio.get_event_loop()
loop.run_until_complete(init(loop))
loop.run_forever()

技術分享圖片

技術分享圖片

參考資料:

  • Python教程 - 廖雪峰的官方網站

Python異步IO