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)

你可能感兴趣的:(Python)