File: benchmark.py

package info (click to toggle)
geventhttpclient 2.3.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,456 kB
  • sloc: ansic: 16,557; python: 3,823; makefile: 24
file content (155 lines) | stat: -rw-r--r-- 3,931 bytes parent folder | download | duplicates (2)
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()