本文目录导读:

我来为您介绍几种Python模拟高并发请求的压力测试方案:
使用 asyncio + aiohttp(推荐)
import asyncio
import aiohttp
import time
from typing import List, Dict
import statistics
class AsyncLoadTester:
def __init__(self, target_url: str, concurrent_users: int, total_requests: int):
self.target_url = target_url
self.concurrent_users = concurrent_users
self.total_requests = total_requests
self.results: List[float] = []
async def single_request(self, session: aiohttp.ClientSession, request_id: int):
"""发送单个请求并记录响应时间"""
start_time = time.time()
try:
async with session.get(self.target_url, timeout=aiohttp.ClientTimeout(total=10)) as response:
elapsed = time.time() - start_time
self.results.append(elapsed)
return request_id, response.status, elapsed
except Exception as e:
elapsed = time.time() - start_time
self.results.append(elapsed)
return request_id, 0, elapsed
async def worker(self, session: aiohttp.ClientSession, worker_id: int, requests_per_worker: int):
"""工作线程:处理一定数量的请求"""
tasks = []
for i in range(requests_per_worker):
request_id = f"worker_{worker_id}_req_{i}"
tasks.append(self.single_request(session, request_id))
return await asyncio.gather(*tasks)
async def run_test(self):
"""执行压力测试"""
print(f"开始压力测试...")
print(f"目标URL: {self.target_url}")
print(f"并发数: {self.concurrent_users}")
print(f"总请求数: {self.total_requests}")
print("-" * 50)
start_time = time.time()
# 计算每个worker处理的请求数
requests_per_worker = self.total_requests // self.concurrent_users
async with aiohttp.ClientSession() as session:
# 创建并发任务
tasks = []
for i in range(self.concurrent_users):
tasks.append(self.worker(session, i, requests_per_worker))
# 并发执行所有任务
all_results = await asyncio.gather(*tasks)
total_time = time.time() - start_time
# 统计结果
self.print_statistics(total_time)
def print_statistics(self, total_time: float):
"""打印测试统计结果"""
if not self.results:
print("没有收集到数据")
return
sorted_results = sorted(self.results)
successful_requests = len([r for r in self.results if r > 0])
failed_requests = len([r for r in self.results if r == 0])
print("\n=== 压力测试结果 ===")
print(f"总耗时: {total_time:.2f} 秒")
print(f"请求总数: {len(self.results)}")
print(f"成功请求: {successful_requests}")
print(f"失败请求: {failed_requests}")
print(f"QPS (每秒请求数): {len(self.results)/total_time:.2f}")
print(f"平均响应时间: {statistics.mean(self.results)*1000:.2f} ms")
print(f"中位响应时间: {statistics.median(self.results)*1000:.2f} ms")
# 百分位响应时间
for percentile in [90, 95, 99]:
index = int(len(sorted_results) * percentile / 100)
print(f"P{percentile} 响应时间: {sorted_results[index]*1000:.2f} ms")
print(f"最小响应时间: {min(self.results)*1000:.2f} ms")
print(f"最大响应时间: {max(self.results)*1000:.2f} ms")
# 使用示例
async def main():
tester = AsyncLoadTester(
target_url="http://localhost:8000/api/endpoint",
concurrent_users=50,
total_requests=1000
)
await tester.run_test()
if __name__ == "__main__":
asyncio.run(main())
使用 threading + requests(简单方案)
import threading
import requests
import time
from queue import Queue
from datetime import datetime
class ThreadedLoadTester:
def __init__(self, target_url: str, num_threads: int, requests_per_thread: int):
self.target_url = target_url
self.num_threads = num_threads
self.requests_per_thread = requests_per_thread
self.results_queue = Queue()
self.success_count = 0
self.failure_count = 0
self.lock = threading.Lock()
def worker(self, thread_id: int):
"""单个工作线程"""
for i in range(self.requests_per_thread):
start_time = time.time()
try:
response = requests.get(
self.target_url,
timeout=5,
headers={'User-Agent': 'LoadTester/1.0'}
)
elapsed = time.time() - start_time
with self.lock:
if response.status_code == 200:
self.success_count += 1
else:
self.failure_count += 1
self.results_queue.put({
'thread_id': thread_id,
'request_id': i,
'status': response.status_code,
'response_time': elapsed,
'timestamp': datetime.now()
})
except Exception as e:
elapsed = time.time() - start_time
with self.lock:
self.failure_count += 1
self.results_queue.put({
'thread_id': thread_id,
'request_id': i,
'status': 0,
'response_time': elapsed,
'error': str(e)
})
def run_test(self):
"""执行压力测试"""
print(f"[{datetime.now()}] 开始压力测试")
print(f"URL: {self.target_url}")
print(f"线程数: {self.num_threads}")
print(f"每个线程请求数: {self.requests_per_thread}")
print(f"总请求数: {self.num_threads * self.requests_per_thread}")
print("-" * 50)
threads = []
start_time = time.time()
# 创建并启动线程
for i in range(self.num_threads):
thread = threading.Thread(target=self.worker, args=(i,))
threads.append(thread)
thread.start()
# 等待所有线程完成
for thread in threads:
thread.join()
total_time = time.time() - start_time
total_requests = self.success_count + self.failure_count
print(f"\n[{datetime.now()}] 测试完成")
print(f"总耗时: {total_time:.2f} 秒")
print(f"总请求数: {total_requests}")
print(f"成功请求: {self.success_count}")
print(f"失败请求: {self.failure_count}")
print(f"QPS: {total_requests/total_time:.2f}")
# 计算平均响应时间
response_times = []
while not self.results_queue.empty():
result = self.results_queue.get()
response_times.append(result['response_time'])
if response_times:
avg_response = sum(response_times) / len(response_times)
print(f"平均响应时间: {avg_response*1000:.2f} ms")
# 使用示例
if __name__ == "__main__":
tester = ThreadedLoadTester(
target_url="http://localhost:8000/api/endpoint",
num_threads=20,
requests_per_thread=50
)
tester.run_test()
使用 Locust 框架(专业方案)
首先安装:pip install locust
创建 locustfile.py:
from locust import HttpUser, task, between, events
import random
class WebsiteUser(HttpUser):
wait_time = between(0.5, 2.5) # 等待时间间隔
def on_start(self):
"""用户开始测试时的初始化"""
print(f"用户 {self.user_id} 开始测试")
@task(3) # 权重3
def view_homepage(self):
"""查看首页"""
self.client.get("/")
@task(2) # 权重2
def view_api_endpoint(self):
"""查看API端点"""
with self.client.get("/api/data", catch_response=True) as response:
if response.status_code == 200:
response.success()
else:
response.failure(f"状态码: {response.status_code}")
@task(1) # 权重1
def submit_form(self):
"""提交表单"""
data = {
"username": f"user_{random.randint(1000, 9999)}",
"action": "test"
}
self.client.post("/api/submit", json=data)
@task(1)
def test_slow_endpoint(self):
"""测试慢接口"""
with self.client.get("/api/slow", catch_response=True, timeout=30) as response:
if response.elapsed.total_seconds() > 5:
response.failure(f"响应时间过长: {response.elapsed.total_seconds():.2f}s")
# 运行命令:locust -f locustfile.py --host=http://localhost:8000
# 然后访问 http://localhost:8089 查看Web界面
高级方案:混合测试策略
import asyncio
import aiohttp
import random
from typing import List, Dict, Any
import json
import time
class AdvancedLoadTester:
"""高级压力测试器,支持混合请求类型"""
def __init__(self, config: Dict[str, Any]):
self.config = config
self.results = []
async def send_request(self, session: aiohttp.ClientSession, request_config: Dict):
"""发送配置的请求"""
method = request_config.get('method', 'GET').upper()
url = request_config['url']
headers = request_config.get('headers', {})
data = request_config.get('data', None)
start_time = time.time()
try:
async with session.request(
method=method,
url=url,
headers=headers,
json=data if method in ['POST', 'PUT'] else None,
params=data if method == 'GET' else None,
timeout=aiohttp.ClientTimeout(total=request_config.get('timeout', 30))
) as response:
elapsed = time.time() - start_time
result = {
'success': response.status < 500,
'status_code': response.status,
'response_time': elapsed,
'url': url,
'method': method
}
if request_config.get('check_response'):
body = await response.text()
result['response_size'] = len(body)
return result
except Exception as e:
return {
'success': False,
'status_code': 0,
'response_time': time.time() - start_time,
'error': str(e),
'url': url,
'method': method
}
async def simulate_realistic_load(self):
"""模拟真实用户行为"""
print("开始模拟真实用户负载...")
async with aiohttp.ClientSession() as session:
tasks = []
# 生成混合请求模式
for i in range(self.config.get('total_users', 100)):
# 每个用户执行一系列操作
user_tasks = []
# 随机选择请求类型
request_types = [
{'method': 'GET', 'url': f"{self.config['base_url']}/api/data"},
{'method': 'POST', 'url': f"{self.config['base_url']}/api/submit",
'data': {'action': 'create'}},
{'method': 'PUT', 'url': f"{self.config['base_url']}/api/update/1"},
{'method': 'DELETE', 'url': f"{self.config['base_url']}/api/delete/1"}
]
# 每个用户执行多个操作
for _ in range(random.randint(1, 5)):
chosen_request = random.choice(request_types)
user_tasks.append(self.send_request(session, chosen_request))
# 模拟用户思考时间
think_time = random.uniform(0.5, 2.0)
await asyncio.sleep(think_time)
tasks.extend(user_tasks)
# 并发执行所有请求
results = await asyncio.gather(*tasks)
self.results.extend(results)
def analyze_results(self):
"""分析测试结果"""
if not self.results:
print("没有测试结果")
return
successful = [r for r in self.results if r['success']]
failed = [r for r in self.results if not r['success']]
response_times = [r['response_time'] for r in self.results]
response_times.sort()
print("=== 测试结果分析 ===")
print(f"总请求数: {len(self.results)}")
print(f"成功: {len(successful)}")
print(f"失败: {len(failed)}")
print(f"成功率: {len(successful)/len(self.results)*100:.2f}%")
print(f"平均响应时间: {sum(response_times)/len(response_times)*1000:.2f}ms")
# 百分位分析
percentiles = [50, 75, 90, 95, 99]
for p in percentiles:
index = int(len(response_times) * p / 100)
print(f"P{p}: {response_times[index]*1000:.2f}ms")
# 使用示例
async def main():
config = {
'base_url': 'http://localhost:8000',
'total_users': 50,
'ramp_up_time': 10, # 秒
'duration': 60, # 秒
}
tester = AdvancedLoadTester(config)
await tester.simulate_realistic_load()
tester.analyze_results()
if __name__ == "__main__":
asyncio.run(main())
使用建议
-
选择合适的工具:
- 简单测试:使用
threading + requests - 高性能测试:使用
asyncio + aiohttp - 专业测试:使用 Locust 框架
- 企业级测试:使用 JMeter + Python脚本
- 简单测试:使用
-
测试注意事项:
- 不要在生产环境直接进行压力测试
- 监控服务器资源使用情况(CPU、内存、网络)
- 从低并发开始逐步增加
- 记录详细的测试日志
-
最佳实践:
- 模拟真实的用户行为模式
- 包含思考时间和随机延迟
- 测试不同的请求类型和负载模式
- 同时监控客户端和服务端指标
这些方案可以根据您的具体需求进行调整和扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播