Building a High‑Performance HTTP Keep‑Alive Benchmark with Python asyncio
This article explains the concept of asynchronous I/O, introduces Python’s provisional asyncio module, and walks through a complete example that creates an HTTP keep‑alive benchmark tool, including code, test environment, performance results, and key asyncio concepts such as event loops, futures, coroutines, and generators.
Asynchronous operations are a common concept in computer systems because collaborating entities often have different processing speeds; in software development the mismatch between CPU and I/O speeds makes asynchronous I/O ubiquitous, appearing in browsers, Node.js, and other frameworks. This article focuses on Python asynchronous I/O.
Python 3.4 introduced the asyncio module to support asynchronous I/O. Although its API is provisional and may change, asyncio is already powerful and worth learning.
Example
asyncio is mainly used for TCP/UDP socket communication, managing many connections without creating a thread per connection. The following example adapts an official snippet to implement an HTTP keep‑alive benchmark tool for diagnosing a web server’s handling capacity.
Functionality overview: every 10 ms create 10 connections (up to a target like 10 k); each connection periodically sends a HEAD request to keep the HTTP keep‑alive alive.
Code
import argparse
import asyncio
import functools
import logging
import random
import urllib.parse
loop = asyncio.get_event_loop()
@asyncio.coroutine
def print_http_headers(no, url, keepalive):
url = urllib.parse.urlsplit(url)
wait_for = functools.partial(asyncio.wait_for, timeout=3, loop=loop)
query = ('HEAD {url.path} HTTP/1.1
'
'Host: {url.hostname}
'
'
').format(url=url).encode('utf-8')
rd, wr = yield from wait_for(asyncio.open_connection(url.hostname, 80))
while True:
wr.write(query)
while True:
line = yield from wait_for(rd.readline())
if not line: # end of connection
wr.close()
return no
line = line.decode('utf-8').rstrip()
if not line: # end of header
break
logging.debug('(%d) HTTP header> %s' % (no, line))
yield from asyncio.sleep(random.randint(1, keepalive//2))
@asyncio.coroutine
def do_requests(args):
conn_pool = set()
waiter = asyncio.Future()
def _on_complete(fut):
conn_pool.remove(fut)
exc, res = fut.exception(), fut.result()
if exc is not None:
logging.info('conn#{} exception'.format(exc))
else:
logging.info('conn#{} result'.format(res))
if not conn_pool:
waiter.set_result('event loop is done')
for i in range(args.connections):
fut = asyncio.async(print_http_headers(i, args.url, args.keepalive))
fut.add_done_callback(_on_complete)
conn_pool.add(fut)
if i % 10 == 0:
yield from asyncio.sleep(0.01)
logging.info((yield from waiter))
def main():
parser = argparse.ArgumentParser(description='asyncli')
parser.add_argument('url', help='page address')
parser.add_argument('-c', '--connections', type=int, default=1,
help='number of connections simultaneously')
parser.add_argument('-k', '--keepalive', type=int, default=60,
help='HTTP keepalive timeout')
args = parser.parse_args()
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')
loop.run_until_complete(do_requests(args))
loop.close()
if __name__ == '__main__':
main()Testing and Analysis
Hardware: CPU 2.3 GHz / 2 cores, RAM 2 GB
Software: CentOS 6.5 (kernel 2.6.32), Python 3.3 (pip install asyncio), nginx 1.4.7
Parameters: ulimit -n 10240; nginx worker connections set to 10240
Start the web server with a single worker process:
# ../sbin/nginx
# ps ax | grep nginx
2007 ? Ss 0:00 nginx: master process ../sbin/nginx
2008 ? S 0:00 nginx: worker process
Run the benchmark tool, creating 10 k connections to nginx’s default test page:
$ python asyncli.py http://10.211.55.8/ -c 10000
nginx log shows an average of 548 requests per second.
Top output (sample):
VIRT RES SHR S %CPU %MEM TIME+ COMMAND
657m 115m 3860 R 60.2 6.2 4:30.02 python
54208 10m 848 R 7.0 0.6 0:30.79 nginx
Conclusion
Python implementation is concise—under 80 lines using only the standard library—illustrating Python’s readability compared to a C/C++ counterpart.
Python’s runtime efficiency is lower; after connections are established, Python consumes roughly ten times the CPU and RAM of nginx, indicating a two‑order‑of‑magnitude performance gap, which reflects the trade‑off between development speed and execution speed.
Single‑threaded asynchronous I/O versus multi‑threaded synchronous I/O: the demo shows async I/O is far more efficient; a 10 k thread model would require >600 MB of stack memory plus heavy context‑switch overhead.
asyncio Core Concepts
The following four concepts are essential when learning asyncio:
Event loop : the single‑threaded loop that drives asynchronous execution.
Future : represents the result of an asynchronous operation.
Coroutine : the function that defines the actual asynchronous task logic.
Generator (yield & yield from) : heavily used in asyncio for delegating execution.
Reference materials:
asyncio – Asynchronous I/O, event loop, coroutines and tasks, https://docs.python.org/3/library/asyncio.html
PEP 3156, Asynchronous IO Support Rebooted: the "asyncio" Module, http://legacy.python.org/dev/peps/pep-3156/
PEP 380, Syntax for Delegating to a Subgenerator, http://legacy.python.org/dev/peps/pep-0380/
PEP 342, Coroutines via Enhanced Generators, http://legacy.python.org/dev/peps/pep-0342/
PEP 255, Simple Generators, http://legacy.python.org/dev/peps/pep-0255/
asyncio source code, http://hg.python.org/cpython/file/3.4/Lib/asyncio/
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
MaGe Linux Operations
Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
