gh-123471: make concurrent iteration over itertools.accumulate thread-safe (#144486)

This commit is contained in:
Pieter Eendebak 2026-03-16 09:53:37 +01:00 committed by GitHub
parent 6f8867a676
commit 3a24856447
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 20 additions and 2 deletions

View file

@ -1,5 +1,5 @@
import unittest
from itertools import batched, chain, combinations_with_replacement, cycle, permutations
from itertools import accumulate, batched, chain, combinations_with_replacement, cycle, permutations
from test.support import threading_helper
@ -16,6 +16,13 @@ def work_iterator(it):
class ItertoolsThreading(unittest.TestCase):
@threading_helper.reap_threads
def test_accumulate(self):
number_of_iterations = 10
for _ in range(number_of_iterations):
it = accumulate(tuple(range(40)))
threading_helper.run_concurrently(work_iterator, nthreads=10, args=[it])
@threading_helper.reap_threads
def test_batched(self):
number_of_iterations = 10

View file

@ -0,0 +1 @@
Make concurrent iteration over :class:`itertools.accumulate` safe under free-threading.

View file

@ -3073,7 +3073,7 @@ accumulate_traverse(PyObject *op, visitproc visit, void *arg)
}
static PyObject *
accumulate_next(PyObject *op)
accumulate_next_lock_held(PyObject *op)
{
accumulateobject *lz = accumulateobject_CAST(op);
PyObject *val, *newtotal;
@ -3105,6 +3105,16 @@ accumulate_next(PyObject *op)
return newtotal;
}
static PyObject *
accumulate_next(PyObject *op)
{
PyObject *result;
Py_BEGIN_CRITICAL_SECTION(op);
result = accumulate_next_lock_held(op);
Py_END_CRITICAL_SECTION()
return result;
}
static PyType_Slot accumulate_slots[] = {
{Py_tp_dealloc, accumulate_dealloc},
{Py_tp_getattro, PyObject_GenericGetAttr},