Last active
July 25, 2024 01:24
-
-
Save rghv404/b38a3bcf00ecbfeff64a64d8d67c4dc2 to your computer and use it in GitHub Desktop.
Quick benchmark of serial vs async vs async_httpx vs threadpool vs processpool
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import asyncio | |
import time | |
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor | |
from contextlib import contextmanager | |
import httpx | |
import requests | |
URL = "https://invitationhomes.com" | |
@contextmanager | |
def timeit(*x): | |
print("\nstarting", x, flush=True) | |
start = time.time() | |
try: | |
yield | |
finally: | |
print(f"done {x} in {time.time() - start:.2f} seconds", flush=True) | |
def normal_requests(unused=None) -> int: | |
resp = requests.get(URL) | |
resp.raise_for_status() | |
return resp.status_code | |
def do_normal_requests(N): | |
return [normal_requests() for _ in range(N)] | |
async def async_requests() -> int: | |
resp = requests.get(URL) | |
resp.raise_for_status() | |
return resp.status_code | |
async def do_async_requests(N): | |
return await asyncio.gather(*(async_requests() for _ in range(N))) | |
async def async_httpx() -> int: | |
async with httpx.AsyncClient(follow_redirects=True, verify=False, timeout=None) as client: | |
response = await client.get(URL) | |
response.raise_for_status() | |
return response.status_code | |
async def do_async_httpx(N): | |
return await asyncio.gather(*(async_httpx() for _ in range(N))) | |
def do_thread_pool_executor(N, W): | |
with ThreadPoolExecutor(max_workers=W) as executor: | |
return [x for x in executor.map(normal_requests, range(N))] | |
def do_process_pool_executor(N, W): | |
with ProcessPoolExecutor(max_workers=W) as executor: | |
return [x for x in executor.map(normal_requests, range(N))] | |
def main(): | |
N = 20 | |
LOOP = 3 | |
print(f"For each below, loop {LOOP} times, each loop {N} batch size.") | |
with timeit("serial"): | |
for _ in range(LOOP): | |
print(">", end="", flush=True) | |
(do_normal_requests(N)) | |
with timeit("async but normal requests"): | |
for _ in range(LOOP): | |
print(">", end="", flush=True) | |
(asyncio.run(do_async_requests(N))) | |
with timeit("async httpx"): | |
for _ in range(LOOP): | |
print(">", end="", flush=True) | |
(asyncio.run(do_async_httpx(N))) | |
Ws = [1, 2, 3, 5, 10, 15, 20] | |
for W in Ws: | |
with timeit("thread pool executor", W): | |
for _ in range(LOOP): | |
print(">", end="", flush=True) | |
(do_thread_pool_executor(N, W)) | |
for W in Ws: | |
with timeit("process pool executor", W): | |
for _ in range(LOOP): | |
print(">", end="", flush=True) | |
(do_process_pool_executor(N, W)) | |
if __name__ == "__main__": | |
main() |
Macbook M1 pro 2021
RAM 16 GB
For each below, loop 3 times, each loop 20 batch size.
starting ('serial',)
>>>done ('serial',) in 39.92 seconds
starting ('async but normal requests',)
>>>done ('async but normal requests',) in 33.38 seconds
starting ('async httpx',)
>>>done ('async httpx',) in 4.21 seconds
starting ('thread pool executor', 1)
>>>done ('thread pool executor', 1) in 31.48 seconds
starting ('thread pool executor', 2)
>>>done ('thread pool executor', 2) in 16.38 seconds
starting ('thread pool executor', 3)
>>>done ('thread pool executor', 3) in 9.51 seconds
starting ('thread pool executor', 5)
>>>done ('thread pool executor', 5) in 6.40 seconds
starting ('thread pool executor', 10)
>>>done ('thread pool executor', 10) in 4.63 seconds
starting ('thread pool executor', 15)
>>>done ('thread pool executor', 15) in 3.25 seconds
starting ('thread pool executor', 20)
>>>done ('thread pool executor', 20) in 4.15 seconds
starting ('process pool executor', 1)
>>>done ('process pool executor', 1) in 26.12 seconds
starting ('process pool executor', 2)
>>>done ('process pool executor', 2) in 16.45 seconds
starting ('process pool executor', 3)
>>>done ('process pool executor', 3) in 11.29 seconds
starting ('process pool executor', 5)
>>>done ('process pool executor', 5) in 8.49 seconds
starting ('process pool executor', 10)
>>>done ('process pool executor', 10) in 7.78 seconds
starting ('process pool executor', 15)
>>>done ('process pool executor', 15) in 8.38 seconds
starting ('process pool executor', 20)
>>>done ('process pool executor', 20) in 10.90 seconds
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Inspired by https://gist.github.com/dongyuzheng/861ee339388803cf135c124dc48a6a0b