1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
import gevent.monkey
gevent.monkey.patch_all()
import geventhttpclient.httplib
geventhttpclient.httplib.patch()
import argparse
import platform
import sys
import time
import gevent.pool
import httpx
import requests
import requests.adapters
import urllib3
from geventhttpclient import httplib2, useragent
class Benchmark:
def __init__(self, url: str, concurrency: int, rounds: int, round_size: int):
self.url = url
self.concurrency = concurrency
self.rounds = rounds
self.round_size = round_size
self.init_client()
def init_client(self):
pass
def request(self):
pass
def request_with_check(self):
content = self.request()
assert content
assert b"html" in content
def start(self):
results = []
for round in range(1, self.rounds + 1):
self.init_client()
now = time.time()
pool = gevent.pool.Pool(size=self.concurrency)
for _ in range(self.round_size):
pool.spawn(self.request_with_check)
pool.join()
delta = time.time() - now
rps = self.round_size / delta
results.append(rps)
print(f"round: {round}, rps: {rps:.1f}")
print(f"total rps: {sum(results) / len(results):.1f}")
class GeventHTTPClientBenchmark(Benchmark):
client: useragent.UserAgent
def init_client(self):
self.client = useragent.UserAgent(concurrency=self.concurrency)
def request(self):
return self.client.urlopen(self.url).content
class RequestsBenchmark(Benchmark):
client: requests.Session
def init_client(self):
self.client = requests.Session()
adapter = requests.adapters.HTTPAdapter(pool_maxsize=self.concurrency, pool_block=True)
self.client.mount("https://", adapter)
self.client.mount("http://", adapter)
def request(self):
return self.client.get(self.url).content
class HttpxBenchmark(Benchmark):
client: httpx.Client
def init_client(self):
# TODO: This should run async
self.client = httpx.Client()
def request(self):
return self.client.get(self.url).content
class Httplib2Benchmark(Benchmark):
client: httplib2.Http
def init_client(self):
self.client = httplib2.Http(concurrency=self.concurrency)
def request(self):
response, content = self.client.request(self.url)
return content
class Urllib3Benchmark(Benchmark):
client: urllib3.PoolManager
def init_client(self):
self.client = urllib3.PoolManager(maxsize=self.concurrency, block=True)
def request(self):
return self.client.request("GET", self.url).data
available_benchmarks = {
"gevent": GeventHTTPClientBenchmark,
"httpx": HttpxBenchmark,
"requests": RequestsBenchmark,
"urllib": Urllib3Benchmark,
"httplib2": Httplib2Benchmark,
}
def arg_parser():
parser = argparse.ArgumentParser()
parser.add_argument("--url", default="http://127.0.0.1/")
parser.add_argument("--concurrency", type=int, default=10)
parser.add_argument("--rounds", type=int, default=3)
parser.add_argument("--round-size", type=int, default=10000)
parser.add_argument(
"-b",
"--benchmark",
nargs="+",
choices=available_benchmarks.keys(),
default=available_benchmarks.keys(),
)
return parser
def main():
args = arg_parser().parse_args().__dict__
benchmark_classes = (available_benchmarks[x] for x in args.pop("benchmark"))
for benchmark_class in benchmark_classes:
print(f"Running {benchmark_class.__name__}".removesuffix("Benchmark"))
benchmark = benchmark_class(**args)
benchmark.start()
print()
print(f"{platform.system()}({platform.machine()}), Python {sys.version.split()[0]}")
if __name__ == "__main__":
main()
|