[Python-checkins] r68625 - sandbox/trunk/io-c/_textio.c
antoine.pitrou
python-checkins at python.org
Fri Jan 16 01:28:23 CET 2009
Author: antoine.pitrou
Date: Fri Jan 16 01:28:23 2009
New Revision: 68625
Log:
Text I/O: speed up small writes by buffering them instead of
sending them immediately.
Modified:
sandbox/trunk/io-c/_textio.c
Modified: sandbox/trunk/io-c/_textio.c
==============================================================================
--- sandbox/trunk/io-c/_textio.c (original)
+++ sandbox/trunk/io-c/_textio.c Fri Jan 16 01:28:23 2009
@@ -473,8 +473,20 @@
int seekable:1;
int telling:1;
+ /* Reads and writes are internally buffered in order to speed things up.
+ However, any read will first flush the write buffer if itsn't empty.
+
+ Please also note that text to be written is first encoded before being
+ buffered. This is necessary so that encoding errors are immediately
+ reported to the caller, but it unfortunately means that the
+ IncrementalEncoder (whose encode() method is always written in Python)
+ becomes a bottleneck for small writes.
+ */
PyObject *decoded_chars; /* buffer for text returned from decoder */
Py_ssize_t decoded_chars_used; /* offset into _decoded_chars for read() */
+ PyObject *pending_bytes; /* list of bytes objects waiting to be
+ written, or NULL */
+ Py_ssize_t pending_bytes_count;
PyObject *snapshot;
/* snapshot is either None, or a tuple (dec_flags, next_input) where
* dec_flags is the second (integer) item of the decoder state and
@@ -521,6 +533,11 @@
Py_CLEAR(self->encoder);
Py_CLEAR(self->decoder);
Py_CLEAR(self->readnl);
+ Py_CLEAR(self->decoded_chars);
+ Py_CLEAR(self->pending_bytes);
+ Py_CLEAR(self->snapshot);
+ self->decoded_chars_used = 0;
+ self->pending_bytes_count = 0;
if (encoding == NULL) {
/* Try os.device_encoding(fileno) */
@@ -722,6 +739,29 @@
return NULL;
}
+/* Flush the internal write buffer. This doesn't explicitly flush the
+ underlying buffered object, though. */
+static int
+_TextIOWrapper_writeflush(PyTextIOWrapperObject *self)
+{
+ PyObject *b, *ret;
+
+ if (self->pending_bytes == NULL)
+ return 0;
+ b = _PyBytes_Join(PyBytes_FromStringAndSize(NULL, 0), self->pending_bytes);
+ if (b == NULL)
+ return -1;
+ ret = PyObject_CallMethodObjArgs(self->buffer,
+ _PyIO_str_write, b, NULL);
+ Py_DECREF(b);
+ if (ret == NULL)
+ return -1;
+ Py_DECREF(ret);
+ Py_CLEAR(self->pending_bytes);
+ self->pending_bytes_count = 0;
+ return 0;
+}
+
static PyObject *
TextIOWrapper_write(PyTextIOWrapperObject *self, PyObject *args)
{
@@ -770,12 +810,25 @@
if (b == NULL)
return NULL;
- ret = PyObject_CallMethodObjArgs(self->buffer, _PyIO_str_write, b, NULL);
- Py_DECREF(b);
- if (ret == NULL)
+ if (self->pending_bytes == NULL) {
+ self->pending_bytes = PyList_New(0);
+ if (self->pending_bytes == NULL) {
+ Py_DECREF(b);
+ return NULL;
+ }
+ self->pending_bytes_count = 0;
+ }
+ if (PyList_Append(self->pending_bytes, b) < 0) {
+ Py_DECREF(b);
return NULL;
- Py_DECREF(ret);
-
+ }
+ self->pending_bytes_count += PyBytes_GET_SIZE(b);
+ Py_DECREF(b);
+ if (self->pending_bytes_count > self->chunk_size || needflush) {
+ if (_TextIOWrapper_writeflush(self) < 0)
+ return NULL;
+ }
+
if (needflush) {
ret = PyObject_CallMethodObjArgs(self->buffer, _PyIO_str_flush, NULL);
if (ret == NULL)
@@ -968,6 +1021,9 @@
CHECK_CLOSED(self);
+ if (_TextIOWrapper_writeflush(self) < 0)
+ return NULL;
+
if (n < 0) {
/* Read everything */
PyObject *bytes = PyObject_CallMethod(self->buffer, "read", NULL);
@@ -1160,6 +1216,9 @@
CHECK_CLOSED(self);
+ if (_TextIOWrapper_writeflush(self) < 0)
+ return NULL;
+
chunked = 0;
while (1) {
@@ -1594,6 +1653,8 @@
goto fail;
}
+ if (_TextIOWrapper_writeflush(self) < 0)
+ return NULL;
res = PyObject_CallMethod((PyObject *)self, "flush", NULL);
if (res == NULL)
goto fail;
@@ -1783,6 +1844,8 @@
CHECK_INITIALIZED(self);
CHECK_CLOSED(self);
self->telling = self->seekable;
+ if (_TextIOWrapper_writeflush(self) < 0)
+ return NULL;
return PyObject_CallMethod(self->buffer, "flush", NULL);
}
More information about the Python-checkins
mailing list