經過python異步通信方式構建高併發壓力測試工具

背景說明

         在工做中,要對一個接口進行壓測,我當時就想經過python本身編寫一個壓力發生器。python

初步方案(單線程循環發送)

經過循環向服務端發送請求,代碼以下:api

#採用單步循環的方式循環測試
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))服務器

 

測試結果以下:session

 

單線程多線程

1併發

開始時間: 1536545804.5258229
結束時間: 1536545879.1070435
運行時間: 74.58122062683105app

2異步

開始時間: 1536546027.6947124
結束時間: 1536546100.3893104
運行時間: 72.69459795951843async

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,若是數量多了,會佔用大量內存,下步進行優化。

相關文章
相關標籤/搜索