zoukankan      html  css  js  c++  java
  • 通过python异步通讯方式构建高并发压力测试工具

    背景说明

             在工作中,要对一个接口进行压测,我当时就想通过python自己编写一个压力发生器。

    初步方案(单线程循环发送)

    通过循环向服务端发送请求,代码如下:

    #采用单步循环的方式循环测试
    import requests,time

    def run(runnum):
        url = "https://api-test.peanut.ai/wechatGrant/load/test1?openId=RP0ulQ4pHDTBWt77ILCs02QGU&bsscode=8167871547864571"
        for i in range(runnum):
            str_res = requests.get(url)
               
    if __name__ == "__main__":
        start_time = time.time()
        run(100)
        end_time = time.time()
        #print("循环次数:",str(counut))
        print("开始时间:",str(start_time))
        print("结束时间:",str(end_time))
        print("运行时间:",str(end_time - start_time))

    测试结果如下:

     

    单线程

    1

    开始时间: 1536545804.5258229
    结束时间: 1536545879.1070435
    运行时间: 74.58122062683105

    2

    开始时间: 1536546027.6947124
    结束时间: 1536546100.3893104
    运行时间: 72.69459795951843

    3

    开始时间: 1536546205.2600951
    结束时间: 1536546270.549498
    运行时间: 65.28940296173096

    4

    开始时间: 1536546368.2361982
    结束时间: 1536546435.7475684
    运行时间: 67.51137018203735

    5

    开始时间: 1536546640.4913867
    结束时间: 1536546712.5064435
    运行时间: 72.015056848526

    运行时间很长,对程序进行了分析,因为循环是单线程并且是同步的,发送请求后,必须等待收到响应,才会发送下一个请求,效率很低,并且循环对压力机的CPU资源消耗较大。

    多线程方案

    考虑通过多线程提高测试效率,代码如下:

    import threading
    import requests
    import time

    url = "https://api-test.peanut.ai/wechatGrant/load/test1?openId=RP0ulQ4pHDTBWt77ILCs02QGU&bsscode=8167871547864571"

    def run_thread(snum,enum):
        for i in range(snum,enum):
            #s = requests.session()
            #关闭长连接
            headers = {'Connection': 'close'}
            str_res = requests.get(url,headers=headers)
            #从发送请求到收到响应消耗的时间,单位微妙。
            etime = str_res.elapsed.microseconds/1000000
           
    threads = []

    for i in range(0,10):
        #循环生成线程
        t = threading.Thread(target=run_thread, args=(0,10))
        threads.append(t)

    if __name__ == "__main__":
        start_time = time.time()
        for dd in range(0,10):
            #启动线程
            threads[dd].start()
        for dd in range(0,10):
            threads[dd].join()

        end_time = time.time()
       
        print("开始时间:",str(start_time))
        print("结束时间:",str(end_time))
        print("运行时间:",str(end_time - start_time))

    测试结果如下:

     

    单线程

    多线程(10)

    1

    开始时间: 1536545804.5258229
    结束时间: 1536545879.1070435
    运行时间: 74.58122062683105

    开始时间: 1536546926.9662883
    结束时间: 1536546935.9247773
    运行时间: 8.958488941192627

    2

    开始时间: 1536546027.6947124
    结束时间: 1536546100.3893104
    运行时间: 72.69459795951843

    开始时间: 1536546962.368912
    结束时间: 1536546970.9876196
    运行时间: 8.618707656860352

    3

    开始时间: 1536546205.2600951
    结束时间: 1536546270.549498
    运行时间: 65.28940296173096

    开始时间: 1536546990.911677
    结束时间: 1536547001.0316806
    运行时间: 10.120003700256348

    4

    开始时间: 1536546368.2361982
    结束时间: 1536546435.7475684
    运行时间: 67.51137018203735

    开始时间: 1536547021.2030604
    结束时间: 1536547030.7051418
    运行时间: 9.502081394195557

    5

    开始时间: 1536546640.4913867
    结束时间: 1536546712.5064435
    运行时间: 72.015056848526

    开始时间: 1536547046.3298163
    结束时间: 1536547054.6956365
    运行时间: 8.365820169448853

    测试效率有很大提高,但也存在问题,当启动线程较多时,压力机资源消耗大,在同一个线程内部,还是同步进行,效率较低。

    异步通讯方案

    asyncio可以实现单线程并发IO操作。如果仅用在客户端,发挥的威力不大。如果把asyncio用在服务器端,例如Web服务器,由于HTTP连接就是IO操作,因此可以用单线程+coroutine实现多用户的高并发支持。

    #采用异步通讯的方式发压
    import requests,time
    import asyncio
    from aiohttp import ClientSession
    import aiohttp


    url = "https://api-test.peanut.ai/wechatGrant/load/test1?openId=RP0ulQ4pHDTBWt77ILCs02QGU&bsscode=8167871547864571"
    tasks = []
    async def run():
        async with ClientSession() as session:
            async with session.get(url) as response:
                response = await response.read()
                #print(response)

    if __name__ == "__main__":
        loop = asyncio.get_event_loop()
        start_time = time.time()
        for i in range(100):
            tasks.append(run())
        end_time = time.time()
        loop.run_until_complete(asyncio.wait(tasks))
        loop.close()
        #print("循环次数:",str(counut))
        print("开始时间:",str(start_time))
        print("结束时间:",str(end_time))
        print("运行时间:",str(end_time - start_time))

    测试结果:

     

    单线程

    多线程(10)

    异步

    1

    开始时间: 1536545804.5258229
    结束时间: 1536545879.1070435
    运行时间: 74.58122062683105

    开始时间: 1536546926.9662883
    结束时间: 1536546935.9247773
    运行时间: 8.958488941192627

    开始时间: 1536565502.732898
    结束时间: 1536565502.732898
    运行时间: 0.0

    2

    开始时间: 1536546027.6947124
    结束时间: 1536546100.3893104
    运行时间: 72.69459795951843

    开始时间: 1536546962.368912
    结束时间: 1536546970.9876196
    运行时间: 8.618707656860352

    开始时间: 1536565502.732898
    结束时间: 1536565502.732898
    运行时间: 0.0

    3

    开始时间: 1536546205.2600951
    结束时间: 1536546270.549498
    运行时间: 65.28940296173096

    开始时间: 1536546990.911677
    结束时间: 1536547001.0316806
    运行时间: 10.120003700256348

    开始时间: 1536565502.732898
    结束时间: 1536565502.732898
    运行时间: 0.0

    4

    开始时间: 1536546368.2361982
    结束时间: 1536546435.7475684
    运行时间: 67.51137018203735

    开始时间: 1536547021.2030604
    结束时间: 1536547030.7051418
    运行时间: 9.502081394195557

    开始时间: 1536565502.732898
    结束时间: 1536565502.732898
    运行时间: 0.0

    5

    开始时间: 1536546640.4913867
    结束时间: 1536546712.5064435
    运行时间: 72.015056848526

    开始时间: 1536547046.3298163
    结束时间: 1536547054.6956365
    运行时间: 8.365820169448853

    开始时间: 1536565502.732898
    结束时间: 1536565502.732898
    运行时间: 0.0

    性能大大提高,但还有一个需要优化的地方,tasks采用的是list,如果数量多了,会占用大量内存,下步进行优化。

  • 相关阅读:
    tarjan无向图缩点
    8、11 T1:入阵曲:复杂度估算,观察规律与性质,数据存储与查询
    容斥系数
    模拟测试12:
    模拟测试11:冷静稳健。
    好的文章
    容器,函数等
    后缀数组:
    HDU5618 Jam's problem again CDQ分治
    P3810 陌上花开 CDQ分治
  • 原文地址:https://www.cnblogs.com/devtest/p/9620811.html
Copyright © 2011-2022 走看看