Benchmark asyncio vs gevent vs native epoll

Everyone knows the asyncio module in python schedules all coroutines in a single thread. That means it helps you code easier, and you can’t gain any performance from it.

But what is the performance of python’s asyncio module? How fast can it run compared to traditional gevent and native epoll ?

Requirements

pip3 <span>install </span>hiredis gevent
pip3 <span>install </span>hiredis gevent
pip3 install hiredis gevent

Enter fullscreen mode Exit fullscreen mode

An optional package uvloop can also be install if working on Linux:

pip3 <span>install </span>uvloop
pip3 <span>install </span>uvloop
pip3 install uvloop

Enter fullscreen mode Exit fullscreen mode

Source

The following code uses both asyncio and gevent to simulate a redis server on port 5000, 5001, and 5002.

They can be tested with redis-benchmark.

content of echo_bench_gevent.py:

<span>import</span> <span>sys</span>
<span>import</span> <span>gevent</span>
<span>import</span> <span>gevent.monkey</span>
<span>import</span> <span>hiredis</span>
<span>from</span> <span>gevent.server</span> <span>import</span> <span>StreamServer</span>
<span>gevent</span><span>.</span><span>monkey</span><span>.</span><span>patch_all</span><span>()</span>
<span>d</span> <span>=</span> <span>{}</span>
<span>def</span> <span>process</span><span>(</span><span>req</span><span>):</span>
<span># only support get/set </span> <span>cmd</span> <span>=</span> <span>req</span><span>[</span><span>0</span><span>].</span><span>lower</span><span>()</span>
<span>if</span> <span>cmd</span> <span>==</span> <span>b</span><span>'set'</span><span>:</span>
<span>d</span><span>[</span><span>req</span><span>[</span><span>1</span><span>]]</span> <span>=</span> <span>req</span><span>[</span><span>2</span><span>]</span>
<span>return</span> <span>b</span><span>"+OK</span><span>\r\n</span><span>"</span>
<span>elif</span> <span>cmd</span> <span>==</span> <span>b</span><span>'get'</span><span>:</span>
<span>v</span> <span>=</span> <span>d</span><span>.</span><span>get</span><span>(</span><span>req</span><span>[</span><span>1</span><span>])</span>
<span>if</span> <span>v</span> <span>is</span> <span>None</span><span>:</span>
<span>return</span> <span>b</span><span>'$-1</span><span>\r\n</span><span>'</span>
<span>else</span><span>:</span>
<span>return</span> <span>b</span><span>'$1</span><span>\r\n</span><span>1</span><span>\r\n</span><span>'</span>
<span>else</span><span>:</span>
<span>print</span><span>(</span><span>cmd</span><span>)</span>
<span>raise</span> <span>NotImplementedError</span><span>()</span>
<span>return</span> <span>b</span><span>''</span>
<span>def</span> <span>handle</span><span>(</span><span>sock</span><span>,</span> <span>addr</span><span>):</span>
<span>reader</span> <span>=</span> <span>hiredis</span><span>.</span><span>Reader</span><span>()</span>
<span>while</span> <span>True</span><span>:</span>
<span>buf</span> <span>=</span> <span>sock</span><span>.</span><span>recv</span><span>(</span><span>4096</span><span>)</span>
<span>if</span> <span>not</span> <span>buf</span><span>:</span>
<span>return</span>
<span>reader</span><span>.</span><span>feed</span><span>(</span><span>buf</span><span>)</span>
<span>while</span> <span>True</span><span>:</span>
<span>req</span> <span>=</span> <span>reader</span><span>.</span><span>gets</span><span>()</span>
<span>if</span> <span>not</span> <span>req</span><span>:</span>
<span>break</span>
<span>sock</span><span>.</span><span>sendall</span><span>(</span><span>process</span><span>(</span><span>req</span><span>))</span>
<span>return</span> <span>0</span>
<span>print</span><span>(</span><span>'serving on 0.0.0.0:5000'</span><span>)</span>
<span>server</span> <span>=</span> <span>StreamServer</span><span>((</span><span>'0.0.0.0'</span><span>,</span> <span>5000</span><span>),</span> <span>handle</span><span>)</span>
<span>server</span><span>.</span><span>serve_forever</span><span>()</span>
<span>import</span> <span>sys</span>
<span>import</span> <span>gevent</span>
<span>import</span> <span>gevent.monkey</span>
<span>import</span> <span>hiredis</span>

<span>from</span> <span>gevent.server</span> <span>import</span> <span>StreamServer</span>
<span>gevent</span><span>.</span><span>monkey</span><span>.</span><span>patch_all</span><span>()</span>

<span>d</span> <span>=</span> <span>{}</span>

<span>def</span> <span>process</span><span>(</span><span>req</span><span>):</span>
    <span># only support get/set </span>    <span>cmd</span> <span>=</span> <span>req</span><span>[</span><span>0</span><span>].</span><span>lower</span><span>()</span>
    <span>if</span> <span>cmd</span> <span>==</span> <span>b</span><span>'set'</span><span>:</span>
        <span>d</span><span>[</span><span>req</span><span>[</span><span>1</span><span>]]</span> <span>=</span> <span>req</span><span>[</span><span>2</span><span>]</span>
        <span>return</span> <span>b</span><span>"+OK</span><span>\r\n</span><span>"</span>
    <span>elif</span> <span>cmd</span> <span>==</span> <span>b</span><span>'get'</span><span>:</span>
        <span>v</span> <span>=</span> <span>d</span><span>.</span><span>get</span><span>(</span><span>req</span><span>[</span><span>1</span><span>])</span>
        <span>if</span> <span>v</span> <span>is</span> <span>None</span><span>:</span>
            <span>return</span> <span>b</span><span>'$-1</span><span>\r\n</span><span>'</span>
        <span>else</span><span>:</span>
            <span>return</span> <span>b</span><span>'$1</span><span>\r\n</span><span>1</span><span>\r\n</span><span>'</span>
    <span>else</span><span>:</span>
        <span>print</span><span>(</span><span>cmd</span><span>)</span>
        <span>raise</span> <span>NotImplementedError</span><span>()</span>
    <span>return</span> <span>b</span><span>''</span>

<span>def</span> <span>handle</span><span>(</span><span>sock</span><span>,</span> <span>addr</span><span>):</span>
    <span>reader</span> <span>=</span> <span>hiredis</span><span>.</span><span>Reader</span><span>()</span>
    <span>while</span> <span>True</span><span>:</span>
        <span>buf</span> <span>=</span> <span>sock</span><span>.</span><span>recv</span><span>(</span><span>4096</span><span>)</span>
        <span>if</span> <span>not</span> <span>buf</span><span>:</span>
            <span>return</span>
        <span>reader</span><span>.</span><span>feed</span><span>(</span><span>buf</span><span>)</span>
        <span>while</span> <span>True</span><span>:</span>
            <span>req</span> <span>=</span> <span>reader</span><span>.</span><span>gets</span><span>()</span>
            <span>if</span> <span>not</span> <span>req</span><span>:</span>
                <span>break</span>
            <span>sock</span><span>.</span><span>sendall</span><span>(</span><span>process</span><span>(</span><span>req</span><span>))</span>
    <span>return</span> <span>0</span>

<span>print</span><span>(</span><span>'serving on 0.0.0.0:5000'</span><span>)</span>
<span>server</span> <span>=</span> <span>StreamServer</span><span>((</span><span>'0.0.0.0'</span><span>,</span> <span>5000</span><span>),</span> <span>handle</span><span>)</span>
<span>server</span><span>.</span><span>serve_forever</span><span>()</span>
import sys import gevent import gevent.monkey import hiredis from gevent.server import StreamServer gevent.monkey.patch_all() d = {} def process(req): # only support get/set cmd = req[0].lower() if cmd == b'set': d[req[1]] = req[2] return b"+OK\r\n" elif cmd == b'get': v = d.get(req[1]) if v is None: return b'$-1\r\n' else: return b'$1\r\n1\r\n' else: print(cmd) raise NotImplementedError() return b'' def handle(sock, addr): reader = hiredis.Reader() while True: buf = sock.recv(4096) if not buf: return reader.feed(buf) while True: req = reader.gets() if not req: break sock.sendall(process(req)) return 0 print('serving on 0.0.0.0:5000') server = StreamServer(('0.0.0.0', 5000), handle) server.serve_forever()

Enter fullscreen mode Exit fullscreen mode

content of echo_bench_asyncio.py:

<span>import</span> <span>asyncio</span>
<span>import</span> <span>hiredis</span>
<span>d</span> <span>=</span> <span>{}</span>
<span>def</span> <span>process</span><span>(</span><span>req</span><span>):</span>
<span>cmd</span> <span>=</span> <span>req</span><span>[</span><span>0</span><span>].</span><span>lower</span><span>()</span>
<span>if</span> <span>cmd</span> <span>==</span> <span>b</span><span>'set'</span><span>:</span>
<span>d</span><span>[</span><span>req</span><span>[</span><span>1</span><span>]]</span> <span>=</span> <span>req</span><span>[</span><span>2</span><span>]</span>
<span>return</span> <span>b</span><span>"+OK</span><span>\r\n</span><span>"</span>
<span>elif</span> <span>cmd</span> <span>==</span> <span>b</span><span>'get'</span><span>:</span>
<span>v</span> <span>=</span> <span>d</span><span>.</span><span>get</span><span>(</span><span>req</span><span>[</span><span>1</span><span>])</span>
<span>if</span> <span>v</span> <span>is</span> <span>None</span><span>:</span>
<span>return</span> <span>b</span><span>'$-1</span><span>\r\n</span><span>'</span>
<span>else</span><span>:</span>
<span>return</span> <span>b</span><span>'$1</span><span>\r\n</span><span>1</span><span>\r\n</span><span>'</span>
<span>elif</span> <span>cmd</span> <span>==</span> <span>b</span><span>'config'</span><span>:</span>
<span>return</span> <span>b</span><span>'-ERROR</span><span>\r\n</span><span>'</span>
<span>else</span><span>:</span>
<span>return</span> <span>b</span><span>'-ERROR</span><span>\r\n</span><span>'</span>
<span>return</span> <span>b</span><span>''</span>
<span>async</span> <span>def</span> <span>echo_server</span><span>(</span><span>reader</span><span>,</span> <span>writer</span><span>):</span>
<span>hireader</span> <span>=</span> <span>hiredis</span><span>.</span><span>Reader</span><span>()</span>
<span>while</span> <span>True</span><span>:</span>
<span>s</span> <span>=</span> <span>await</span> <span>reader</span><span>.</span><span>read</span><span>(</span><span>4096</span><span>)</span>
<span>if</span> <span>not</span> <span>s</span><span>:</span>
<span>break</span>
<span>hireader</span><span>.</span><span>feed</span><span>(</span><span>s</span><span>)</span>
<span>while</span> <span>True</span><span>:</span>
<span>req</span> <span>=</span> <span>hireader</span><span>.</span><span>gets</span><span>()</span>
<span>if</span> <span>not</span> <span>req</span><span>:</span>
<span>break</span>
<span>res</span> <span>=</span> <span>process</span><span>(</span><span>req</span><span>)</span>
<span>writer</span><span>.</span><span>write</span><span>(</span><span>res</span><span>)</span>
<span>await</span> <span>writer</span><span>.</span><span>drain</span><span>()</span>
<span>return</span> <span>0</span>
<span>async</span> <span>def</span> <span>main</span><span>():</span>
<span>server</span> <span>=</span> <span>await</span> <span>asyncio</span><span>.</span><span>start_server</span><span>(</span><span>echo_server</span><span>,</span> <span>'0.0.0.0'</span><span>,</span> <span>5001</span><span>)</span>
<span>print</span><span>(</span><span>'serving on {}'</span><span>.</span><span>format</span><span>(</span><span>server</span><span>.</span><span>sockets</span><span>[</span><span>0</span><span>].</span><span>getsockname</span><span>()))</span>
<span>await</span> <span>server</span><span>.</span><span>serve_forever</span><span>()</span>
<span>return</span> <span>0</span>
<span>asyncio</span><span>.</span><span>run</span><span>(</span><span>main</span><span>())</span>
<span>import</span> <span>asyncio</span>
<span>import</span> <span>hiredis</span>

<span>d</span> <span>=</span> <span>{}</span>

<span>def</span> <span>process</span><span>(</span><span>req</span><span>):</span>
    <span>cmd</span> <span>=</span> <span>req</span><span>[</span><span>0</span><span>].</span><span>lower</span><span>()</span>
    <span>if</span> <span>cmd</span> <span>==</span> <span>b</span><span>'set'</span><span>:</span>
        <span>d</span><span>[</span><span>req</span><span>[</span><span>1</span><span>]]</span> <span>=</span> <span>req</span><span>[</span><span>2</span><span>]</span>
        <span>return</span> <span>b</span><span>"+OK</span><span>\r\n</span><span>"</span>
    <span>elif</span> <span>cmd</span> <span>==</span> <span>b</span><span>'get'</span><span>:</span>
        <span>v</span> <span>=</span> <span>d</span><span>.</span><span>get</span><span>(</span><span>req</span><span>[</span><span>1</span><span>])</span>
        <span>if</span> <span>v</span> <span>is</span> <span>None</span><span>:</span>
            <span>return</span> <span>b</span><span>'$-1</span><span>\r\n</span><span>'</span>
        <span>else</span><span>:</span>
            <span>return</span> <span>b</span><span>'$1</span><span>\r\n</span><span>1</span><span>\r\n</span><span>'</span>
    <span>elif</span> <span>cmd</span> <span>==</span> <span>b</span><span>'config'</span><span>:</span>
        <span>return</span> <span>b</span><span>'-ERROR</span><span>\r\n</span><span>'</span>
    <span>else</span><span>:</span>
        <span>return</span> <span>b</span><span>'-ERROR</span><span>\r\n</span><span>'</span>
    <span>return</span> <span>b</span><span>''</span>

<span>async</span> <span>def</span> <span>echo_server</span><span>(</span><span>reader</span><span>,</span> <span>writer</span><span>):</span>
    <span>hireader</span> <span>=</span> <span>hiredis</span><span>.</span><span>Reader</span><span>()</span>
    <span>while</span> <span>True</span><span>:</span>
        <span>s</span> <span>=</span> <span>await</span> <span>reader</span><span>.</span><span>read</span><span>(</span><span>4096</span><span>)</span>
        <span>if</span> <span>not</span> <span>s</span><span>:</span>
            <span>break</span>
        <span>hireader</span><span>.</span><span>feed</span><span>(</span><span>s</span><span>)</span>
        <span>while</span> <span>True</span><span>:</span>
            <span>req</span> <span>=</span> <span>hireader</span><span>.</span><span>gets</span><span>()</span>
            <span>if</span> <span>not</span> <span>req</span><span>:</span>
                <span>break</span>
            <span>res</span> <span>=</span> <span>process</span><span>(</span><span>req</span><span>)</span>
            <span>writer</span><span>.</span><span>write</span><span>(</span><span>res</span><span>)</span>
            <span>await</span> <span>writer</span><span>.</span><span>drain</span><span>()</span>
    <span>return</span> <span>0</span>

<span>async</span> <span>def</span> <span>main</span><span>():</span>
    <span>server</span> <span>=</span> <span>await</span> <span>asyncio</span><span>.</span><span>start_server</span><span>(</span><span>echo_server</span><span>,</span> <span>'0.0.0.0'</span><span>,</span> <span>5001</span><span>)</span>
    <span>print</span><span>(</span><span>'serving on {}'</span><span>.</span><span>format</span><span>(</span><span>server</span><span>.</span><span>sockets</span><span>[</span><span>0</span><span>].</span><span>getsockname</span><span>()))</span>
    <span>await</span> <span>server</span><span>.</span><span>serve_forever</span><span>()</span>
    <span>return</span> <span>0</span>

<span>asyncio</span><span>.</span><span>run</span><span>(</span><span>main</span><span>())</span>
import asyncio import hiredis d = {} def process(req): cmd = req[0].lower() if cmd == b'set': d[req[1]] = req[2] return b"+OK\r\n" elif cmd == b'get': v = d.get(req[1]) if v is None: return b'$-1\r\n' else: return b'$1\r\n1\r\n' elif cmd == b'config': return b'-ERROR\r\n' else: return b'-ERROR\r\n' return b'' async def echo_server(reader, writer): hireader = hiredis.Reader() while True: s = await reader.read(4096) if not s: break hireader.feed(s) while True: req = hireader.gets() if not req: break res = process(req) writer.write(res) await writer.drain() return 0 async def main(): server = await asyncio.start_server(echo_server, '0.0.0.0', 5001) print('serving on {}'.format(server.sockets[0].getsockname())) await server.serve_forever() return 0 asyncio.run(main())

Enter fullscreen mode Exit fullscreen mode

content of echo_bench_asyncio_uvloop.py:

<span>import</span> <span>asyncio</span>
<span>import</span> <span>hiredis</span>
<span>d</span> <span>=</span> <span>{}</span>
<span>def</span> <span>process</span><span>(</span><span>req</span><span>):</span>
<span>cmd</span> <span>=</span> <span>req</span><span>[</span><span>0</span><span>].</span><span>lower</span><span>()</span>
<span>if</span> <span>cmd</span> <span>==</span> <span>b</span><span>'set'</span><span>:</span>
<span>d</span><span>[</span><span>req</span><span>[</span><span>1</span><span>]]</span> <span>=</span> <span>req</span><span>[</span><span>2</span><span>]</span>
<span>return</span> <span>b</span><span>"+OK</span><span>\r\n</span><span>"</span>
<span>elif</span> <span>cmd</span> <span>==</span> <span>b</span><span>'get'</span><span>:</span>
<span>v</span> <span>=</span> <span>d</span><span>.</span><span>get</span><span>(</span><span>req</span><span>[</span><span>1</span><span>])</span>
<span>if</span> <span>v</span> <span>is</span> <span>None</span><span>:</span>
<span>return</span> <span>b</span><span>'$-1</span><span>\r\n</span><span>'</span>
<span>else</span><span>:</span>
<span>return</span> <span>b</span><span>'$1</span><span>\r\n</span><span>1</span><span>\r\n</span><span>'</span>
<span>elif</span> <span>cmd</span> <span>==</span> <span>b</span><span>'config'</span><span>:</span>
<span>return</span> <span>b</span><span>'-ERROR</span><span>\r\n</span><span>'</span>
<span>else</span><span>:</span>
<span>return</span> <span>b</span><span>'-ERROR</span><span>\r\n</span><span>'</span>
<span>return</span> <span>b</span><span>''</span>
<span>async</span> <span>def</span> <span>echo_server</span><span>(</span><span>reader</span><span>,</span> <span>writer</span><span>):</span>
<span>hireader</span> <span>=</span> <span>hiredis</span><span>.</span><span>Reader</span><span>()</span>
<span>while</span> <span>True</span><span>:</span>
<span>s</span> <span>=</span> <span>await</span> <span>reader</span><span>.</span><span>read</span><span>(</span><span>4096</span><span>)</span>
<span>if</span> <span>not</span> <span>s</span><span>:</span>
<span>break</span>
<span>hireader</span><span>.</span><span>feed</span><span>(</span><span>s</span><span>)</span>
<span>while</span> <span>True</span><span>:</span>
<span>req</span> <span>=</span> <span>hireader</span><span>.</span><span>gets</span><span>()</span>
<span>if</span> <span>not</span> <span>req</span><span>:</span>
<span>break</span>
<span>res</span> <span>=</span> <span>process</span><span>(</span><span>req</span><span>)</span>
<span>writer</span><span>.</span><span>write</span><span>(</span><span>res</span><span>)</span>
<span>await</span> <span>writer</span><span>.</span><span>drain</span><span>()</span>
<span>return</span> <span>0</span>
<span>async</span> <span>def</span> <span>main</span><span>():</span>
<span>server</span> <span>=</span> <span>await</span> <span>asyncio</span><span>.</span><span>start_server</span><span>(</span><span>echo_server</span><span>,</span> <span>'0.0.0.0'</span><span>,</span> <span>5002</span><span>)</span>
<span>print</span><span>(</span><span>'serving on {}'</span><span>.</span><span>format</span><span>(</span><span>server</span><span>.</span><span>sockets</span><span>[</span><span>0</span><span>].</span><span>getsockname</span><span>()))</span>
<span>await</span> <span>server</span><span>.</span><span>serve_forever</span><span>()</span>
<span>return</span> <span>0</span>
<span>try</span><span>:</span>
<span>import</span> <span>uvloop</span>
<span>uvloop</span><span>.</span><span>install</span><span>()</span>
<span>print</span><span>(</span><span>'uvloop is enabled'</span><span>)</span>
<span>except</span> <span>ImportError</span><span>:</span>
<span>print</span><span>(</span><span>'uvloop is not available'</span><span>)</span>
<span>asyncio</span><span>.</span><span>run</span><span>(</span><span>main</span><span>())</span>
<span>import</span> <span>asyncio</span>
<span>import</span> <span>hiredis</span>

<span>d</span> <span>=</span> <span>{}</span>

<span>def</span> <span>process</span><span>(</span><span>req</span><span>):</span>
    <span>cmd</span> <span>=</span> <span>req</span><span>[</span><span>0</span><span>].</span><span>lower</span><span>()</span>
    <span>if</span> <span>cmd</span> <span>==</span> <span>b</span><span>'set'</span><span>:</span>
        <span>d</span><span>[</span><span>req</span><span>[</span><span>1</span><span>]]</span> <span>=</span> <span>req</span><span>[</span><span>2</span><span>]</span>
        <span>return</span> <span>b</span><span>"+OK</span><span>\r\n</span><span>"</span>
    <span>elif</span> <span>cmd</span> <span>==</span> <span>b</span><span>'get'</span><span>:</span>
        <span>v</span> <span>=</span> <span>d</span><span>.</span><span>get</span><span>(</span><span>req</span><span>[</span><span>1</span><span>])</span>
        <span>if</span> <span>v</span> <span>is</span> <span>None</span><span>:</span>
            <span>return</span> <span>b</span><span>'$-1</span><span>\r\n</span><span>'</span>
        <span>else</span><span>:</span>
            <span>return</span> <span>b</span><span>'$1</span><span>\r\n</span><span>1</span><span>\r\n</span><span>'</span>
    <span>elif</span> <span>cmd</span> <span>==</span> <span>b</span><span>'config'</span><span>:</span>
        <span>return</span> <span>b</span><span>'-ERROR</span><span>\r\n</span><span>'</span>
    <span>else</span><span>:</span>
        <span>return</span> <span>b</span><span>'-ERROR</span><span>\r\n</span><span>'</span>
    <span>return</span> <span>b</span><span>''</span>

<span>async</span> <span>def</span> <span>echo_server</span><span>(</span><span>reader</span><span>,</span> <span>writer</span><span>):</span>
    <span>hireader</span> <span>=</span> <span>hiredis</span><span>.</span><span>Reader</span><span>()</span>
    <span>while</span> <span>True</span><span>:</span>
        <span>s</span> <span>=</span> <span>await</span> <span>reader</span><span>.</span><span>read</span><span>(</span><span>4096</span><span>)</span>
        <span>if</span> <span>not</span> <span>s</span><span>:</span>
            <span>break</span>
        <span>hireader</span><span>.</span><span>feed</span><span>(</span><span>s</span><span>)</span>
        <span>while</span> <span>True</span><span>:</span>
            <span>req</span> <span>=</span> <span>hireader</span><span>.</span><span>gets</span><span>()</span>
            <span>if</span> <span>not</span> <span>req</span><span>:</span>
                <span>break</span>
            <span>res</span> <span>=</span> <span>process</span><span>(</span><span>req</span><span>)</span>
            <span>writer</span><span>.</span><span>write</span><span>(</span><span>res</span><span>)</span>
            <span>await</span> <span>writer</span><span>.</span><span>drain</span><span>()</span>
    <span>return</span> <span>0</span>

<span>async</span> <span>def</span> <span>main</span><span>():</span>
    <span>server</span> <span>=</span> <span>await</span> <span>asyncio</span><span>.</span><span>start_server</span><span>(</span><span>echo_server</span><span>,</span> <span>'0.0.0.0'</span><span>,</span> <span>5002</span><span>)</span>
    <span>print</span><span>(</span><span>'serving on {}'</span><span>.</span><span>format</span><span>(</span><span>server</span><span>.</span><span>sockets</span><span>[</span><span>0</span><span>].</span><span>getsockname</span><span>()))</span>
    <span>await</span> <span>server</span><span>.</span><span>serve_forever</span><span>()</span>
    <span>return</span> <span>0</span>

<span>try</span><span>:</span>
    <span>import</span> <span>uvloop</span>
    <span>uvloop</span><span>.</span><span>install</span><span>()</span>
    <span>print</span><span>(</span><span>'uvloop is enabled'</span><span>)</span>
<span>except</span> <span>ImportError</span><span>:</span>
    <span>print</span><span>(</span><span>'uvloop is not available'</span><span>)</span>

<span>asyncio</span><span>.</span><span>run</span><span>(</span><span>main</span><span>())</span>
import asyncio import hiredis d = {} def process(req): cmd = req[0].lower() if cmd == b'set': d[req[1]] = req[2] return b"+OK\r\n" elif cmd == b'get': v = d.get(req[1]) if v is None: return b'$-1\r\n' else: return b'$1\r\n1\r\n' elif cmd == b'config': return b'-ERROR\r\n' else: return b'-ERROR\r\n' return b'' async def echo_server(reader, writer): hireader = hiredis.Reader() while True: s = await reader.read(4096) if not s: break hireader.feed(s) while True: req = hireader.gets() if not req: break res = process(req) writer.write(res) await writer.drain() return 0 async def main(): server = await asyncio.start_server(echo_server, '0.0.0.0', 5002) print('serving on {}'.format(server.sockets[0].getsockname())) await server.serve_forever() return 0 try: import uvloop uvloop.install() print('uvloop is enabled') except ImportError: print('uvloop is not available') asyncio.run(main())

Enter fullscreen mode Exit fullscreen mode

Start servers

python3 echo_bench_gevent.py <span># will listen on port 5000</span>
python3 echo_bench_asyncio.py <span># will listen on port 5001</span>
python3 echo_bench_asyncio_uvloop.py <span># will listen on port 5002</span>
python3 echo_bench_gevent.py          <span># will listen on port 5000</span>
python3 echo_bench_asyncio.py         <span># will listen on port 5001</span>
python3 echo_bench_asyncio_uvloop.py  <span># will listen on port 5002</span>
python3 echo_bench_gevent.py # will listen on port 5000 python3 echo_bench_asyncio.py # will listen on port 5001 python3 echo_bench_asyncio_uvloop.py # will listen on port 5002

Enter fullscreen mode Exit fullscreen mode

Test

redis-benchmark <span>-p</span> 5000 <span>-t</span> get <span>-n</span> 100000 <span>-r</span> 100000000
redis-benchmark <span>-p</span> 5001 <span>-t</span> get <span>-n</span> 100000 <span>-r</span> 100000000
redis-benchmark <span>-p</span> 5002 <span>-t</span> get <span>-n</span> 100000 <span>-r</span> 100000000
redis-benchmark <span>-p</span> 5000 <span>-t</span> get <span>-n</span> 100000 <span>-r</span> 100000000
redis-benchmark <span>-p</span> 5001 <span>-t</span> get <span>-n</span> 100000 <span>-r</span> 100000000
redis-benchmark <span>-p</span> 5002 <span>-t</span> get <span>-n</span> 100000 <span>-r</span> 100000000
redis-benchmark -p 5000 -t get -n 100000 -r 100000000 redis-benchmark -p 5001 -t get -n 100000 -r 100000000 redis-benchmark -p 5002 -t get -n 100000 -r 100000000

Enter fullscreen mode Exit fullscreen mode

Result

Mode Python 3.9 Python 3.11
gevent 34281.80 requests / second 32258.07 requests / second
asyncio 40144.52 requests / second 51652.89 requests / second
asyncio + uvloop 64102.57 requests / second 66577.90 requests / second

Native epoll

Redis is implemented with epoll in C, and we can test redis directly:

redis-benchmark <span>-p</span> 6379 <span>-t</span> get <span>-n</span> 100000 <span>-r</span> 100000000
redis-benchmark <span>-p</span> 6379 <span>-t</span> get <span>-n</span> 100000 <span>-r</span> 100000000
redis-benchmark -p 6379 -t get -n 100000 -r 100000000

Enter fullscreen mode Exit fullscreen mode

Output:

75244.55 requests per second
75244.55 requests per second
75244.55 requests per second

Enter fullscreen mode Exit fullscreen mode

Conclusion

  • asyncio is 50% faster than gevent in Python 3.11
  • asyncio can run twice as fast as gevent with uvloop.
  • asyncio can go up to 68% of a native epoll program.
  • asyncio can go up to 88% of a native epoll program with uvloop.

原文链接:Benchmark asyncio vs gevent vs native epoll

© 版权声明
THE END
喜欢就支持一下吧
点赞14 分享
A good idea without action is worth nothing.
如果没有切实执行,再好的点子也是徒劳
评论 抢沙发

请登录后发表评论

    暂无评论内容