Skip to content

Commit e1d32b2

Browse files
committed
streams: Optimize stream.write for bytes & bytearrays
1 parent 907d747 commit e1d32b2

File tree

4 files changed

+35
-6
lines changed

4 files changed

+35
-6
lines changed

tests/test_tcp.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ async def handle_client(reader, writer):
2424

2525
data = await reader.readexactly(len(B_DATA))
2626
self.assertEqual(data, B_DATA)
27-
writer.writelines([b'SP', bytearray(b'A'), memoryview(b'M')])
27+
writer.writelines([b'S', b'P'])
28+
writer.write(bytearray(b'A'))
29+
writer.write(memoryview(b'M'))
2830

2931
await writer.drain()
3032
writer.close()

uvloop/handles/stream.pyx

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ cdef class _StreamWriteContext:
1212
uv.uv_buf_t uv_buf
1313
Py_buffer py_buf
1414

15+
bint used_buf
16+
object data
17+
1518
UVStream stream
1619

1720
bint closed
@@ -21,8 +24,10 @@ cdef class _StreamWriteContext:
2124
return
2225

2326
self.closed = 1
24-
PyBuffer_Release(&self.py_buf) # void
27+
if self.used_buf:
28+
PyBuffer_Release(&self.py_buf) # void
2529
self.req.data = NULL
30+
self.data = None
2631
IF not DEBUG:
2732
self.stream = None
2833
Py_DECREF(self)
@@ -33,11 +38,26 @@ cdef class _StreamWriteContext:
3338
ctx = _StreamWriteContext.__new__(_StreamWriteContext)
3439
ctx.stream = None
3540
ctx.closed = 1
41+
ctx.used_buf = 0
3642

3743
ctx.req.data = <void*> ctx
3844

39-
PyObject_GetBuffer(data, &ctx.py_buf, PyBUF_SIMPLE)
40-
ctx.uv_buf = uv.uv_buf_init(<char*>ctx.py_buf.buf, ctx.py_buf.len)
45+
if PyBytes_CheckExact(data):
46+
ctx.data = data
47+
ctx.uv_buf.base = PyBytes_AS_STRING(data)
48+
ctx.uv_buf.len = Py_SIZE(data)
49+
50+
elif PyByteArray_CheckExact(data):
51+
ctx.data = data
52+
ctx.uv_buf.base = PyByteArray_AS_STRING(data)
53+
ctx.uv_buf.len = Py_SIZE(data)
54+
55+
else:
56+
PyObject_GetBuffer(data, &ctx.py_buf, PyBUF_SIMPLE)
57+
ctx.used_buf = 1
58+
ctx.uv_buf.base = <char*>ctx.py_buf.buf
59+
ctx.uv_buf.len = ctx.py_buf.len
60+
4161
ctx.stream = stream
4262

4363
IF DEBUG:

uvloop/includes/python.pxd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@ cdef extern from "Python.h":
44
void* PyMem_Calloc(size_t nelem, size_t elsize) # Python >= 3.5!
55
void PyMem_Free(void *p)
66

7+
char* PyByteArray_AS_STRING(object o)
8+
int PyByteArray_CheckExact(object o)
9+
710
object PyUnicode_EncodeFSDefault(object)
811
void PyErr_SetInterrupt() nogil

uvloop/loop.pyx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ from .includes cimport system
1111
from .includes.python cimport PyMem_Malloc, PyMem_Free, \
1212
PyMem_Calloc, PyMem_Realloc, \
1313
PyUnicode_EncodeFSDefault, \
14-
PyErr_SetInterrupt
14+
PyErr_SetInterrupt, \
15+
PyByteArray_AS_STRING, \
16+
PyByteArray_CheckExact
1517

1618
from libc.stdint cimport uint64_t
1719
from libc.string cimport memset, strerror
@@ -22,7 +24,9 @@ from cpython cimport PyErr_CheckSignals, PyErr_Occurred
2224
from cpython cimport PyThread_get_thread_ident
2325
from cpython cimport Py_INCREF, Py_DECREF, Py_XDECREF, Py_XINCREF
2426
from cpython cimport PyObject_GetBuffer, PyBuffer_Release, PyBUF_SIMPLE, \
25-
Py_buffer, PyBytes_AsString
27+
Py_buffer, PyBytes_AsString, PyBytes_CheckExact, \
28+
Py_SIZE, PyBytes_AS_STRING
29+
2630
from cpython cimport PyErr_CheckSignals
2731

2832

0 commit comments

Comments
 (0)