Skip to content

Commit b310767

Browse files
committed
Use Cython 'async def' coroutines without @asyncio.coroutine
This commit boosts the performance of 'async def' coroutines compiled with Cython up to 50%.
1 parent c560258 commit b310767

File tree

5 files changed

+47
-16
lines changed

5 files changed

+47
-16
lines changed

Makefile

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,14 @@ distclean: clean clean-libuv
2626
compile: clean
2727
echo "DEF DEBUG = 0" > uvloop/__debug.pxi
2828
cython -3 uvloop/loop.pyx; rm uvloop/__debug.*
29+
@echo "$$UVLOOP_BUILD_PATCH_SCRIPT" | python
2930
python setup.py build_ext --inplace
3031

3132

3233
debug: clean
3334
echo "DEF DEBUG = 1" > uvloop/__debug.pxi
3435
cython -3 -a -p uvloop/loop.pyx; rm uvloop/__debug.*
36+
@echo "$$UVLOOP_BUILD_PATCH_SCRIPT" | python
3537
python setup.py build_ext --inplace
3638

3739

@@ -50,3 +52,39 @@ sdist: clean compile test sdist-libuv
5052

5153
release: clean compile test sdist-libuv
5254
python setup.py sdist upload
55+
56+
57+
# Script to patch Cython 'async def' coroutines to have a 'tp_iter' slot,
58+
# which makes them compatible with 'yield from' without the
59+
# `asyncio.coroutine` decorator.
60+
define UVLOOP_BUILD_PATCH_SCRIPT
61+
import re
62+
63+
with open('uvloop/loop.c', 'rt') as f:
64+
src = f.read()
65+
66+
src = re.sub(
67+
r'''
68+
\s* offsetof\(__pyx_CoroutineObject,\s*gi_weakreflist\),
69+
\s* 0,
70+
\s* 0,
71+
\s* __pyx_Coroutine_methods,
72+
\s* __pyx_Coroutine_memberlist,
73+
\s* __pyx_Coroutine_getsets,
74+
''',
75+
76+
r'''
77+
offsetof(__pyx_CoroutineObject, gi_weakreflist),
78+
__Pyx_Coroutine_await, /* tp_iter */
79+
0,
80+
__pyx_Coroutine_methods,
81+
__pyx_Coroutine_memberlist,
82+
__pyx_Coroutine_getsets,
83+
''',
84+
85+
src, flags=re.X)
86+
87+
with open('uvloop/loop.c', 'wt') as f:
88+
f.write(src)
89+
endef
90+
export UVLOOP_BUILD_PATCH_SCRIPT

tests/test_sockets.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import asyncio
12
import socket
23

34
from uvloop import _testbase as tb
@@ -22,12 +23,15 @@ def srv_gen():
2223
yield tb.write(b'O')
2324
yield tb.write(b'K')
2425

25-
async def client(sock, addr):
26-
await self.loop.sock_connect(sock, addr)
27-
data = await self.recv_all(sock, 4)
26+
# We use @asyncio.coroutine & `yield from` to test
27+
# the compatibility of Cython's 'async def' coroutines.
28+
@asyncio.coroutine
29+
def client(sock, addr):
30+
yield from self.loop.sock_connect(sock, addr)
31+
data = yield from self.recv_all(sock, 4)
2832
self.assertEqual(data, b'helo')
29-
await self.loop.sock_sendall(sock, b'ehlo' * _SIZE)
30-
data = await self.recv_all(sock, 2)
33+
yield from self.loop.sock_sendall(sock, b'ehlo' * _SIZE)
34+
data = yield from self.recv_all(sock, 2)
3135
self.assertEqual(data, b'OK')
3236

3337
with tb.tcp_server(srv_gen) as srv:

uvloop/includes/stdlib.pxi

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ cdef aio_ensure_future = asyncio.ensure_future
2323
cdef aio_gather = asyncio.gather
2424
cdef aio_wait = asyncio.wait
2525
cdef aio_logger = asyncio.log.logger
26-
cdef aio_coroutine = asyncio.coroutine
2726
cdef aio__check_resolved_address = asyncio.base_events._check_resolved_address
2827
cdef aio_iscoroutine = asyncio.iscoroutine
2928
cdef aio_iscoroutinefunction = asyncio.iscoroutinefunction

uvloop/loop.pyx

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,6 @@ cdef class Loop:
10341034

10351035
return self._getaddrinfo(host, port, family, type, proto, flags, 1)
10361036

1037-
@aio_coroutine
10381037
async def getnameinfo(self, sockaddr, int flags=0):
10391038
cdef:
10401039
AddrInfo ai_cnt
@@ -1089,7 +1088,6 @@ cdef class Loop:
10891088

10901089
return await self._getnameinfo(ai.ai_addr, flags)
10911090

1092-
@aio_coroutine
10931091
async def create_server(self, protocol_factory, host=None, port=None,
10941092
*,
10951093
int family=uv.AF_UNSPEC,
@@ -1215,7 +1213,6 @@ cdef class Loop:
12151213

12161214
return server
12171215

1218-
@aio_coroutine
12191216
async def create_connection(self, protocol_factory, host=None, port=None, *,
12201217
ssl=None, family=0, proto=0, flags=0, sock=None,
12211218
local_addr=None, server_hostname=None):
@@ -1365,7 +1362,6 @@ cdef class Loop:
13651362
else:
13661363
return tr, protocol
13671364

1368-
@aio_coroutine
13691365
async def create_unix_server(self, protocol_factory, str path=None,
13701366
*, backlog=100, sock=None, ssl=None):
13711367
"""A coroutine which creates a UNIX Domain Socket server.
@@ -1432,7 +1428,6 @@ cdef class Loop:
14321428
server._add_server(pipe)
14331429
return server
14341430

1435-
@aio_coroutine
14361431
async def create_unix_connection(self, protocol_factory, path, *,
14371432
ssl=None, sock=None,
14381433
server_hostname=None):
@@ -1712,7 +1707,6 @@ cdef class Loop:
17121707
def set_default_executor(self, executor):
17131708
self._default_executor = executor
17141709

1715-
@aio_coroutine
17161710
async def __subprocess_run(self, protocol_factory, args,
17171711
stdin=subprocess_PIPE,
17181712
stdout=subprocess_PIPE,
@@ -1803,7 +1797,6 @@ cdef class Loop:
18031797
return self.__subprocess_run(protocol_factory, args, shell=False,
18041798
**kwargs)
18051799

1806-
@aio_coroutine
18071800
async def connect_read_pipe(self, proto_factory, pipe):
18081801
"""Register read pipe in event loop. Set the pipe to non-blocking mode.
18091802
@@ -1829,7 +1822,6 @@ cdef class Loop:
18291822
raise
18301823
return transp, proto
18311824

1832-
@aio_coroutine
18331825
async def connect_write_pipe(self, proto_factory, pipe):
18341826
"""Register write pipe in event loop.
18351827
@@ -1929,7 +1921,6 @@ cdef class Loop:
19291921

19301922
return True
19311923

1932-
@aio_coroutine
19331924
async def create_datagram_endpoint(self, protocol_factory,
19341925
local_addr=None, remote_addr=None, *,
19351926
family=0, proto=0, flags=0,

uvloop/server.pyx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ cdef class Server:
3232
def __repr__(self):
3333
return '<%s sockets=%r>' % (self.__class__.__name__, self.sockets)
3434

35-
@aio_coroutine
3635
async def wait_closed(self):
3736
if self._servers is None or self._waiters is None:
3837
return

0 commit comments

Comments
 (0)