Skip to content

gh-124397: Add free-threading support for iterators.#148894

Open
rhettinger wants to merge 8 commits intopython:mainfrom
rhettinger:iterator_synchronization
Open

gh-124397: Add free-threading support for iterators.#148894
rhettinger wants to merge 8 commits intopython:mainfrom
rhettinger:iterator_synchronization

Conversation

@rhettinger
Copy link
Copy Markdown
Contributor

@rhettinger rhettinger commented Apr 22, 2026

@rhettinger rhettinger added the type-feature A feature request or enhancement label Apr 22, 2026
@rhettinger rhettinger changed the title Issue-124397: Add free-threading support for iterators. gh-124397: Add free-threading support for iterators. Apr 22, 2026
@rhettinger rhettinger marked this pull request as draft April 22, 2026 22:39
@rhettinger rhettinger requested a review from colesbury April 23, 2026 02:00
@rhettinger rhettinger force-pushed the iterator_synchronization branch from 21fca13 to 4c2bad0 Compare April 23, 2026 02:33
@rhettinger rhettinger marked this pull request as ready for review April 23, 2026 02:52
Copy link
Copy Markdown
Contributor

@colesbury colesbury left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment thread Doc/library/threading.rst

import threading

source = range(5)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem like a very compelling example because range() you can iterate over range concurrent from multiple threads already.

Maybe something like a simple generator would be more useful as an example?

Comment thread Doc/library/threading.rst

.. doctest::

import threading
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs >>> for doctest to run. Alternatively, use .. code-block:: python

Comment thread Lib/threading.py
Comment on lines +863 to +864
self.iterator = iter(iterable)
self.lock = Lock()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please prefix .iterator and .lock with _ so that they aren't considered part of serialize's public API.

Comment thread Lib/threading.py
'Barrier', 'BrokenBarrierError', 'Timer', 'ThreadError',
'setprofile', 'settrace', 'local', 'stack_size',
'excepthook', 'ExceptHookArgs', 'gettrace', 'getprofile',
'serialize', 'synchronized', 'concurrent_tee',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest we not add these to __all__. Doing that complicates life for anyone unfortunate enough to have done a * import while already using these names from other imports. Code reads better if people explicitly spell them out anyways, threading.serialize(...) or @threading.synchronized_iteratorare more self explanatory than the bare words. Not putting them inall` helps encourage that. Leave a comment here mentioning that they were intentionally excluded.

Comment thread Lib/threading.py
Comment on lines +898 to +914
def synchronized(func):
"""Wrap an iterator-returning callable to make its iterators thread-safe.

Existing itertools and more-itertools can be wrapped so that their
iterator instances are serialized.

For example, itertools.count does not make thread-safe instances,
but that is easily fixed with:

atomic_counter = synchronized(itertools.count)

Can also be used as a decorator for generator functions definitions
so that the generator instances are serialized::

import time

@synchronized
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def synchronized(func):
"""Wrap an iterator-returning callable to make its iterators thread-safe.
Existing itertools and more-itertools can be wrapped so that their
iterator instances are serialized.
For example, itertools.count does not make thread-safe instances,
but that is easily fixed with:
atomic_counter = synchronized(itertools.count)
Can also be used as a decorator for generator functions definitions
so that the generator instances are serialized::
import time
@synchronized
def synchronized_iterator(func):
"""Wrap an iterator-returning callable to make its iterators thread-safe.
Existing itertools and more-itertools can be wrapped so that their
iterator instances are serialized.
For example, itertools.count does not make thread-safe instances,
but that is easily fixed with:
atomic_counter = threading.synchronized_iterator(itertools.count)
Can also be used as a decorator for generator functions definitions
so that the generator instances are serialized::
import time
@threading.synchronized_iterator

synchronized is a very generic name, I suggest making its specific purpose explicit.

Comment thread Lib/threading.py
## Synchronization tools for iterators #####################

class serialize:
"""Wrap a non-concurrent iterator with a lock to enforce sequential access.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an example to the docstring.

Similar to my other suggestion should we name this serialize_iterator given how generic of a word serialize is?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding a test that an iterator __next__ raising an exception behaves properly.

Comment thread Lib/threading.py

## Synchronization tools for iterators #####################

class serialize:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a subclass of Iterable? (suggested by @serhiy-storchaka on the issue)

Comment thread Doc/library/threading.rst
allow reliable concurrency support to be added to ordinary iterators and
iterator-producing callables.

The :class:`serialize` wrapper lets multiple threads share a single iterator and
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To bikeshed the name a topic https://discuss.python.org/t/name-for-new-itertools-object-to-make-iterators-thread-safe/90394 was created. serialize is not my favorite, but on the topic there was no strong support for any of the other names either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants