This commit is contained in:
Yuriy Yuriev
2026-05-22 15:19:18 +07:00
parent d30f011897
commit 679cb40ec1
+16 -8
View File
@@ -4,6 +4,7 @@
Использование: Использование:
python load_test.py --n 5 python load_test.py --n 5
python load_test.py --n 10 --url https://example.com --time 15 python load_test.py --n 10 --url https://example.com --time 15
python load_test.py --n 10 --parallel 3 # не более 3 одновременных запусков
""" """
import asyncio import asyncio
@@ -11,14 +12,13 @@ import sys
import time import time
import argparse import argparse
from pathlib import Path from pathlib import Path
from dataclasses import dataclass, field from dataclasses import dataclass
from typing import List, Optional from typing import List, Optional
sys.path.insert(0, str(Path(__file__).parent)) sys.path.insert(0, str(Path(__file__).parent))
import psutil import psutil
from config.settings import settings
from core.logger import setup_logger from core.logger import setup_logger
from managers.proxy_manager import ProxyManager from managers.proxy_manager import ProxyManager
from services.browser_service import BrowserService from services.browser_service import BrowserService
@@ -47,7 +47,12 @@ async def run_one_browser(
url: str, url: str,
visit_time: int, visit_time: int,
results: List[BrowserResult], results: List[BrowserResult],
launch_sem: asyncio.Semaphore,
) -> None: ) -> None:
# Семафор ограничивает сколько браузеров стартует одновременно.
# Когда браузер поднялся (AsyncCamoufox.__aenter__ завершён), семафор освобождается
# и следующий браузер может начать запуск. Так избегаем race на ресурсы ОС.
async with launch_sem:
t0 = time.perf_counter() t0 = time.perf_counter()
try: try:
result = await browser_service.visit_page(url, reading_time=visit_time) result = await browser_service.visit_page(url, reading_time=visit_time)
@@ -67,10 +72,10 @@ async def run_one_browser(
print(f" [Browser {index:>2}] EXCEPTION: {e}{duration:.1f}s") print(f" [Browser {index:>2}] EXCEPTION: {e}{duration:.1f}s")
async def run_load_test(n: int, url: str, visit_time: int) -> None: async def run_load_test(n: int, url: str, visit_time: int, parallel: int) -> None:
print(f"\n{'='*60}") print(f"\n{'='*60}")
print(f" Нагрузочный тест") print(f" Нагрузочный тест")
print(f" Браузеров: {n} | URL: {url} | Время: {visit_time}s") print(f" Браузеров: {n} | Одновременный запуск: {parallel} | URL: {url} | Время: {visit_time}s")
# Инфо о системе # Инфо о системе
mem = psutil.virtual_memory() mem = psutil.virtual_memory()
@@ -91,13 +96,14 @@ async def run_load_test(n: int, url: str, visit_time: int) -> None:
ram_before = _mem_mb() ram_before = _mem_mb()
print(f" RAM до старта: {ram_before:.0f} MB") print(f" RAM до старта: {ram_before:.0f} MB")
print(f"\n Запускаем {n} браузеров...\n") print(f"\n Запускаем {n} браузеров (волнами по {parallel})...\n")
launch_sem = asyncio.Semaphore(parallel)
wall_start = time.perf_counter() wall_start = time.perf_counter()
tasks = [ tasks = [
asyncio.create_task( asyncio.create_task(
run_one_browser(i + 1, browser_service, url, visit_time, results) run_one_browser(i + 1, browser_service, url, visit_time, results, launch_sem)
) )
for i in range(n) for i in range(n)
] ]
@@ -137,13 +143,15 @@ async def run_load_test(n: int, url: str, visit_time: int) -> None:
def main(): def main():
parser = argparse.ArgumentParser(description="Load test: N параллельных браузеров") parser = argparse.ArgumentParser(description="Load test: N параллельных браузеров")
parser.add_argument("--n", type=int, default=3, help="Число параллельных браузеров (по умолчанию: 3)") parser.add_argument("--n", type=int, default=3, help="Всего браузеров (по умолчанию: 3)")
parser.add_argument("--parallel", type=int, default=2, help="Макс. одновременных запусков (по умолчанию: 2)")
parser.add_argument("--url", type=str, default="https://httpbin.org/headers", help="URL для посещения") parser.add_argument("--url", type=str, default="https://httpbin.org/headers", help="URL для посещения")
parser.add_argument("--time", type=int, default=10, dest="visit_time", help="Время посещения в секундах (по умолчанию: 10)") parser.add_argument("--time", type=int, default=10, dest="visit_time", help="Время посещения в секундах (по умолчанию: 10)")
args = parser.parse_args() args = parser.parse_args()
parallel = min(args.parallel, args.n)
try: try:
asyncio.run(run_load_test(args.n, args.url, args.visit_time)) asyncio.run(run_load_test(args.n, args.url, args.visit_time, parallel))
except KeyboardInterrupt: except KeyboardInterrupt:
print("\nПрервано.") print("\nПрервано.")