Python3 使用多線程、協程併發請求的比較

1、安裝相關的庫

pip install gevent requests aiohttp

2、實際代碼演示

import asyncio
import time
from gevent import monkey; monkey.patch_all()
import requests
import aiohttp
import sys
import threading
import gevent
from urllib.request import urlopen
'''
loop.run_until_complete(future)
運行直到 future ( Future 的實例 ) 被完成。
如果參數是 coroutine object ,將被隱式調度爲 asyncio.Task 來運行。
返回 Future 的結果 或者引發相關異常。
'''
# http://127.0.0.1:8000/test/ 是本地實現的一個接口 每次請求耗時兩秒左右,同步請求的話沒增加一個請求都會增加耗時兩秒。本例使用請發併發多個請求。預期耗時兩秒左右。


async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def aio_request_main():
    async with aiohttp.ClientSession() as session:
        html = await fetch(session, 'http://127.0.0.1:8000/test/')
        print(html)


async def say_after(name):
    print('%s start...' % name)
    url = 'http://127.0.0.1:8000/test/'
    res = requests.get(url)
    print(res.text)
    return res

async def main():
    task1 = asyncio.create_task(say_after('任務1'))
    task2 = asyncio.create_task(say_after('任務2'))
    # await task1
    # await task2
    asyncio.wait([task1, task2]) # 這個方法雖然可以運行任務,但是會等待任務的返回可等待對象,由於requests庫返回的response對象不是可等待對象,所以最終會報異常


def run(num):
    print('%s start...' % num)
    url = 'http://127.0.0.1:8000/test/'
    res = requests.get(url)
    print(res.text)
    

if __name__ == '__main__':
    start_time = time.time()
    # 嘗試使用 asyncio 開啓協程任務,但由於requests庫是同步的,因此它返回的response不是可等待對象,因此最終執行效果是同步的
    if len(sys.argv) > 1 and sys.argv[1] == '1':
        asyncio.run(main())
    # 使用基於asyncio 的三方庫 aiohttp ,它實現了異步請求客戶端,有aiohttp可發起異步的網絡請求並返回可等待對象,因此執行效果是併發的
    elif len(sys.argv) > 1 and sys.argv[1] == '2':
        loop = asyncio.get_event_loop()
        tasks = []
        for i in range(2):
            task = loop.create_task(aio_request_main())
            tasks.append(task)
        loop.run_until_complete(asyncio.wait(tasks))
    # 簡單 粗暴的使用多線程來併發請求
    elif len(sys.argv) > 1 and sys.argv[1] == '3':
        ts = [threading.Thread(target=run, args=(num, )) for num in range(2)]
        [item.start() for item in ts]
        [item.join() for item in ts]
    # 使用gevent模塊併發協程
    elif len(sys.argv) > 1 and sys.argv[1] == '4':
        gevent.joinall(
            [
                gevent.spawn(run, (1, )),
                gevent.spawn(run, (2, )),
            ]
        )
    print('耗時:', time.time() - start_time)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章