https://github.com/python/cpython/commit/1a80214f11f1a6ddcea19e2c40719c746a163f02
commit: 1a80214f11f1a6ddcea19e2c40719c746a163f02
branch: main
author: Pieter Eendebak <[email protected]>
committer: markshannon <[email protected]>
date: 2025-01-29T09:15:24Z
summary:
gh-126703: Add freelists for list and tuple iterators (GH-128592)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2025-01-07-19-26-40.gh-issue-126703.9i-S5t.rst
M Include/internal/pycore_freelist_state.h
M Objects/listobject.c
M Objects/object.c
M Objects/tupleobject.c
diff --git a/Include/internal/pycore_freelist_state.h
b/Include/internal/pycore_freelist_state.h
index 2ccd1ac055b747..7c252f5b570c13 100644
--- a/Include/internal/pycore_freelist_state.h
+++ b/Include/internal/pycore_freelist_state.h
@@ -11,6 +11,8 @@ extern "C" {
# define PyTuple_MAXSAVESIZE 20 // Largest tuple to save on freelist
# define Py_tuple_MAXFREELIST 2000 // Maximum number of tuples of each size
to save
# define Py_lists_MAXFREELIST 80
+# define Py_list_iters_MAXFREELIST 10
+# define Py_tuple_iters_MAXFREELIST 10
# define Py_dicts_MAXFREELIST 80
# define Py_dictkeys_MAXFREELIST 80
# define Py_floats_MAXFREELIST 100
@@ -40,6 +42,8 @@ struct _Py_freelists {
struct _Py_freelist ints;
struct _Py_freelist tuples[PyTuple_MAXSAVESIZE];
struct _Py_freelist lists;
+ struct _Py_freelist list_iters;
+ struct _Py_freelist tuple_iters;
struct _Py_freelist dicts;
struct _Py_freelist dictkeys;
struct _Py_freelist slices;
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2025-01-07-19-26-40.gh-issue-126703.9i-S5t.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-07-19-26-40.gh-issue-126703.9i-S5t.rst
new file mode 100644
index 00000000000000..dcd5f449c98ef3
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-07-19-26-40.gh-issue-126703.9i-S5t.rst
@@ -0,0 +1 @@
+Improve performance of iterating over lists and tuples by using a freelist for
the iterator objects.
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 099e65c0c25fed..f4a269e4d7b284 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -3903,15 +3903,17 @@ PyTypeObject PyListIter_Type = {
static PyObject *
list_iter(PyObject *seq)
{
- _PyListIterObject *it;
-
if (!PyList_Check(seq)) {
PyErr_BadInternalCall();
return NULL;
}
- it = PyObject_GC_New(_PyListIterObject, &PyListIter_Type);
- if (it == NULL)
- return NULL;
+ _PyListIterObject *it = _Py_FREELIST_POP(_PyListIterObject, list_iters);
+ if (it == NULL) {
+ it = PyObject_GC_New(_PyListIterObject, &PyListIter_Type);
+ if (it == NULL) {
+ return NULL;
+ }
+ }
it->it_index = 0;
it->it_seq = (PyListObject *)Py_NewRef(seq);
_PyObject_GC_TRACK(it);
@@ -3924,7 +3926,8 @@ listiter_dealloc(PyObject *self)
_PyListIterObject *it = (_PyListIterObject *)self;
_PyObject_GC_UNTRACK(it);
Py_XDECREF(it->it_seq);
- PyObject_GC_Del(it);
+ assert(Py_IS_TYPE(self, &PyListIter_Type));
+ _Py_FREELIST_FREE(list_iters, it, PyObject_GC_Del);
}
static int
diff --git a/Objects/object.c b/Objects/object.c
index cd48d2f75ba490..fdff16138201a0 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -923,6 +923,8 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists,
int is_finalization)
clear_freelist(&freelists->tuples[i], is_finalization, free_object);
}
clear_freelist(&freelists->lists, is_finalization, free_object);
+ clear_freelist(&freelists->list_iters, is_finalization, free_object);
+ clear_freelist(&freelists->tuple_iters, is_finalization, free_object);
clear_freelist(&freelists->dicts, is_finalization, free_object);
clear_freelist(&freelists->dictkeys, is_finalization, PyMem_Free);
clear_freelist(&freelists->slices, is_finalization, free_object);
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index 7fe8553030a02e..60af9e40e3fe83 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -993,7 +993,8 @@ tupleiter_dealloc(PyObject *self)
_PyTupleIterObject *it = _PyTupleIterObject_CAST(self);
_PyObject_GC_UNTRACK(it);
Py_XDECREF(it->it_seq);
- PyObject_GC_Del(it);
+ assert(Py_IS_TYPE(self, &PyTupleIter_Type));
+ _Py_FREELIST_FREE(tuple_iters, it, PyObject_GC_Del);
}
static int
@@ -1119,15 +1120,16 @@ PyTypeObject PyTupleIter_Type = {
static PyObject *
tuple_iter(PyObject *seq)
{
- _PyTupleIterObject *it;
-
if (!PyTuple_Check(seq)) {
PyErr_BadInternalCall();
return NULL;
}
- it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type);
- if (it == NULL)
- return NULL;
+ _PyTupleIterObject *it = _Py_FREELIST_POP(_PyTupleIterObject, tuple_iters);
+ if (it == NULL) {
+ it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type);
+ if (it == NULL)
+ return NULL;
+ }
it->it_index = 0;
it->it_seq = (PyTupleObject *)Py_NewRef(seq);
_PyObject_GC_TRACK(it);
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]