summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Misc/ACKS1
-rw-r--r--Misc/NEWS8
-rw-r--r--Objects/listobject.c34
3 files changed, 37 insertions, 6 deletions
diff --git a/Misc/ACKS b/Misc/ACKS
index 4ddd6a3..8f1cdcd 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -62,6 +62,7 @@ Finn Bock
Paul Boddie
Matthew Boedicker
David Bolen
+Duncan Booth
Jurjen Bos
Peter Bosch
Eric Bouck
diff --git a/Misc/NEWS b/Misc/NEWS
index fbd572f..ce4f90b 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -118,6 +118,14 @@ Core and builtins
same as split() except that it scans the string from the end
working towards the beginning. See SF feature request 801847.
+- in a thread on comp.lang.python, several people noted that list()
+ was much slower than in 2.1 and earlier versions of Python, when used
+ to create new lists from existing lists. Duncan Booth did some
+ research that uncovered an optimisation that, for lists below
+ about 100 elements, was actually slower than the normal case. The
+ special case criteria have been tightened to rectify the performance
+ regression.
+
Extension modules
-----------------
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 47673be..66e4460 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -2234,6 +2234,13 @@ list_richcompare(PyObject *v, PyObject *w, int op)
return PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op);
}
+/* empirically determined threshold for activating an optimisation
+ * in list_fill() - 100 seems close to optimum for current CPUs and
+ * compilers, as of December '03.
+ * see also comment in list_fill().
+ */
+#define LISTFILL_OPT_THRESHOLD 100
+
/* Adapted from newer code by Tim */
static int
list_fill(PyListObject *result, PyObject *v)
@@ -2242,14 +2249,29 @@ list_fill(PyListObject *result, PyObject *v)
int n; /* guess for result list size */
int i;
+ /* if source is destination, we're done. */
+ if (v == (PyObject *)result)
+ return 0;
+
n = result->ob_size;
- /* Special-case list(a_list), for speed. */
- if (PyList_Check(v)) {
- if (v == (PyObject *)result)
- return 0; /* source is destination, we're done */
- return list_ass_slice(result, 0, n, v);
- }
+ /* Special-case list(a_list), for speed:
+ * - if the source has 0 elements, there's nothing to copy.
+ * - if the source has more than a threshold number of elements
+ * slice assignment is a faster way of filling the target
+ * (the exact threshold is subject to empirical determination).
+ * Also special case any other zero length sequence, including
+ * subclasses of list, there being nothing to copy.
+ */
+ if (PyList_CheckExact(v)) {
+ i = ((PyListObject*)v)->ob_size;
+ if (i == 0)
+ return 0;
+ if (i > LISTFILL_OPT_THRESHOLD)
+ return list_ass_slice(result, 0, n, v);
+ } else
+ if (PySequence_Check(v) && PySequence_Size(v) == 0)
+ return 0;
/* Empty previous contents */
if (n != 0) {