Index: Modules/_pickle.c =================================================================== --- Modules/_pickle.c (revision 71084) +++ Modules/_pickle.c (working copy) @@ -1407,11 +1407,6 @@ assert(iter != NULL); - /* XXX: I think this function could be made faster by avoiding the - iterator interface and fetching objects directly from list using - PyList_GET_ITEM. - */ - if (self->proto == 0) { /* APPENDS isn't available; do one at a time. */ for (;;) { @@ -1499,10 +1494,66 @@ return -1; } +/* This is a variant of batch_list() above, specialized for lists (with no + * support for list subclasses). Like batch_list(), we batch up chunks of + * MARK item item ... item APPENDS + * opcode sequences. Calling code should have arranged to first create an + * empty list, or list-like object, for the APPENDS to operate on. + * Returns 0 on success, -1 on error. + * + * This version is considerably faster than batch_list(), if less general. + * + * Note that this only works for protocols > 0. + */ static int +batch_list_exact(PicklerObject *self, PyObject *obj) +{ + PyObject *item = NULL; + int i, j; + Py_ssize_t list_size; + + const char mark_op = MARK; + const char append_op = APPEND; + const char appends_op = APPENDS; + + assert(obj != NULL); + assert(self->proto > 0); + + list_size = PyList_GET_SIZE(obj); + if (list_size == 1) { + item = PyList_GET_ITEM(obj, 0); + if (save(self, item, 0) < 0) + return -1; + if (pickler_write(self, &append_op, 1) < 0) + return -1; + + return 0; /* and we're done! */ + } + + /* More than one item to save; write in batches of BATCHSIZE. */ + j = 0; + do { + i = 0; + if (pickler_write(self, &mark_op, 1) < 0) + return -1; + while (j < list_size) { + item = PyList_GET_ITEM(obj, j); + if (save(self, item, 0) < 0) + return -1; + j++; + if (++i == BATCHSIZE) + break; + } + if (pickler_write(self, &appends_op, 1) < 0) + return -1; + } while (i == BATCHSIZE); + + return 0; +} + +static int save_list(PicklerObject *self, PyObject *obj) { - PyObject *iter; char header[3]; int len; int status = 0; @@ -1533,11 +1584,22 @@ if (len != 0) { /* Save the list elements. */ - iter = PyObject_GetIter(obj); - if (iter == NULL) - goto error; - status = batch_list(self, iter); - Py_DECREF(iter); + if (PyList_CheckExact(obj) && self->proto > 0) { + if (Py_EnterRecursiveCall(" while pickling an object") == 0) { + status = batch_list_exact(self, obj); + Py_LeaveRecursiveCall(); + } + } + else { + PyObject *iter = PyObject_GetIter(obj); + if (iter == NULL) + goto error; + if (Py_EnterRecursiveCall(" while pickling an object") == 0) { + status = batch_list(self, iter); + Py_LeaveRecursiveCall(); + } + Py_DECREF(iter); + } } if (0) {