asyncio与gevent并发性能测试

asyncio与gevent并发性能测试

在对网站进行扫描或者暴破时需要对网站进行高并发操作,然而requests+concurrent多线程性能上不太理想,了解到python用得比较多的并发库有asynciogevent,于是就有了如下测试。

0x00 协程

asynciogevent都是基于携程来进行并发操作的。协程也被称为微线程。
协程只是在单一的线程里进行切换不同的协程,因此无法使用多CPU能力,对于CPU密集型程序还是使用多进程比较好。
协程相比较进程和线程来说占用的内容更少,同样的线程切换更多的是靠操作系统来控制,而协程的执行则由我们自己控制。
并发原理:当其中一个协程遇到io等待时,将会切换到另一个协程继续运行。

0x01 grequests

grequests是对requestsgevent库的封装
测试代码:

#!/usr/bin/python3.7
import grequests
import time
    
if __name__ == '__main__':
    start = time.time()
    greenlets = []
    for _ in range(10):
        greenlets.append(grequests.get("http://150.xx.xx.xx"))
    rets = grequests.map(greenlets)
    for ret in rets:
        print(ret)
    end = time.time()
    print("grequests visit_async tasks %.2f seconds" % (end - start))

grequests.map()参数说明:
def grequests.map(requests, stream=False, size=None, exception_handler=None, gtimeout=None)

参数说明备注
size 协程的并发度(相当于线程数) 当一个协程在IO等待时,会将CPU交给其他协程
exception_handler 异常处理函数 用于处理单个请求出现异常的函数
gtimeout 设置所有请求的超时时间  

grequests的底层是request,所以它也支持回调函数:

def print_url(r, *args, **kwargs):
    print(r.url)
res = grequests.get(url, callback=print_url)

测试结果:

 
grequsts并发性能测试

0x02 asyncio + uvloop

由于gevent的猴子补丁的缘故,requests可以和gevent结合使用,但是在不清楚内部实现的情况下,requests库经常比较容易出现Failed to establish a new connection:的情况,在使用grequests库之后该情况得到解决。
uvloop是用Cython写的,目前不支持windows,它基于libuv.uvloop使得asyncio更快,基于性能的测试接近于go。
可以通过两种方式来使用uvloop:

import uvloop
import asyncio

#1. 通过设置策略
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) 
#2. 直接创建一个新的event_loop
asyncio.set_event_loop(uvloop.new_event_loop())

由于asycnio采用异步操作,它在使用的过程中所有的模块也都得是异步的,所以在进行http请求时也需要异步,即aiohttp
测试代码:

#!/usr/bin/python3.7
import asyncio
import aiohttp
import uvloop
import time

async def access_url(url):
    async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=False)) as session:
        async with session.get(url) as response:
            status_code = response.status
            print(status_code)

async def visit_async():
    start = time.time()
    tasks = []
    for _ in range(10):
        tasks.append(access_url("http://150.xx.xx.xx"))
    await asyncio.gather(*tasks)
    end = time.time()
    print("asyncio visit_async tasks %.2f seconds" % (end - start))

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    future = asyncio.ensure_future(visit_async())
    asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
    loop.run_until_complete(future)

测试结果:

 
asyncio 并发性能测试

0x03 优缺点

asyncio由于是异步操作,且代码库生态不够完善,部分异步代码库存在问题可能查不到,且编写代码时行数较多,影响阅读,而且代库函数全部重构,上手有难度,但是并发执行的速度较快,对于暴破、端口扫描等比较适用。
gevent采用了requests模块,在使用了猴子补丁后对于扫描网站路径等可以有效即时针对扫描结果进行深层扫描。

请求内容:

 
请求内容

参考:


 
 
原文地址:https://www.cnblogs.com/leijiangtao/p/11957406.html