GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-123271: Make builtin zip method safe under free-threading by eendebakpt · Pull Request #123272 · python/cpython

Conversation

@eendebakpt

@eendebakpt eendebakpt commented Aug 23, 2024 •
edited by bedevere-app Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

In this PR we make zip safe under free-threading.

  • Issue: Builtin zip method is not safe under free-threading #123271

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@eendebakpt
Make builtin zip method safe under free-threading
f9d44d1
@eendebakpt
eendebakpt requested a review from ericsnowcurrently as a code owner August 23, 2024 20:18
@bedevere-app bedevere-app Bot mentioned this pull request Aug 23, 2024
Builtin zip method is not safe under free-threading #123271
Closed
@bedevere-app bedevere-app Bot added the awaiting review label Aug 23, 2024
@eendebakpt eendebakpt changed the title gh-123271: Make builtin zip method safe under free-threading Draft: gh-123271: Make builtin zip method safe under free-threading Aug 23, 2024
eendebakpt and others added 2 commits August 23, 2024 22:23
@eendebakpt
whitespace
2530fbe
@blurb-it
📜🤖 Added by blurb_it.
1b592d2
@Eclips4
Eclips4 requested a review from colesbury August 24, 2024 06:42
Eclips4
Eclips4 reviewed Aug 24, 2024
View reviewed changes
Comment thread Python/bltinmodule.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Misc/NEWS.d/next/Core_and_Builtins/2024-08-23-21-20-34.gh-issue-123271.xeVViR.rst Outdated
@@ -0,0 +1 @@
Make :meth:`zip` safe under free-threading.

@Eclips4 Eclips4 Aug 24, 2024

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Suggested change
Make :meth:`zip` safe under free-threading.
Make :func:`zip` thread-safe without the :term:`GIL`.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@eendebakpt eendebakpt Aug 24, 2024

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Even with this PR the zip function is not thread-safe: when iterating over zip(range(100), range(100)) one can obtain a tuple (2,3). What does PR (hopefully) does is modifying the code so that the interpreter does not crash. For this reason I would like to be careful with the term "thread-safe". I choose not to make zip fully thread safe because of the performance impact, see the discussion in #120496

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@Eclips4 Eclips4 Aug 25, 2024

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Thanks for clarifying. The word safe is a bit confusing, I guess a lot of other people would read it as thread-safe. I think we need to clarify the reason why zip isn't safe in free-threaded build.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/test/test_zip_threading.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

eendebakpt and others added 3 commits August 24, 2024 17:29
@eendebakpt @Eclips4
Update Python/bltinmodule.c
bd9d9fb
Co-authored-by: Kirill Podoprigora <[email protected]>
@eendebakpt
cleanup test
d199600
@eendebakpt
review comments
54eb509
colesbury
colesbury reviewed Aug 26, 2024
View reviewed changes
Comment thread Python/bltinmodule.c Outdated
Comment on lines +2974 to +2979
#ifdef Py_GIL_DISABLED
int reuse_tuple = 0;
#else
int reuse_tuple = Py_REFCNT(result) == 1;
#endif
if (reuse_tuple) {

@colesbury colesbury Aug 26, 2024

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I think we want to enable re-use under certain conditions. We should probably put the logic in some internal function, possibly in pycore_object.h. I think the condition for the free-threaded build is:

  1. ob_tid matches _Py_ThreadId()
  2. ob_ref_local is 1
  3. ob_ref_shared is 0

The logic is that no other thread calling zip_next can re-use lz->result because of the thread id condition (condition 1). And no thread outside of zip_next can incref that object because the combined conditions ensure that lz->result is the only reference.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@eendebakpt eendebakpt Aug 27, 2024

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

@colesbury Thanks for the hint! I implementeded the suggestion

  • I placed the logic in a single method _Py_Reuse_Immutable_Object so we can use the trick code for several other cases (e.g. itertools.pairwise, enumerate). The location and name of the new method can be changed though
  • I re-ordered the three conditions because I suspect that ob_ref_local is most informative and fastest to check
  • I am now checking ob_ref_shared to be zero, but perhaps we should check on Py_ARITHMETIC_RIGHT_SHIFT(Py_ssize_t, ob_ref_shared , _Py_REF_SHARED_SHIFT)?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
colesbury
colesbury reviewed Aug 26, 2024
View reviewed changes
Comment thread Misc/NEWS.d/next/Core_and_Builtins/2024-08-23-21-20-34.gh-issue-123271.xeVViR.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

eendebakpt and others added 6 commits August 27, 2024 17:04
@eendebakpt
enable re-use of tuples in the free-threading build
755a862
@eendebakpt @colesbury
Update Misc/NEWS.d/next/Core_and_Builtins/2024-08-23-21-20-34.gh-issu…
8c0fe40
…e-123271.xeVViR.rst

Co-authored-by: Sam Gross <[email protected]>
@eendebakpt
move to pycore_object.h
1e8799f
@eendebakpt
Merge branch 'main' into zip_ft
bd3cc27
@eendebakpt
whitespace
4fa48dd
@eendebakpt
cleanup
0416f0b
@eendebakpt eendebakpt changed the title Draft: gh-123271: Make builtin zip method safe under free-threading gh-123271: Make builtin zip method safe under free-threading Aug 27, 2024
@colesbury
colesbury self-requested a review August 27, 2024 16:45
colesbury
colesbury reviewed Aug 27, 2024
View reviewed changes

@colesbury colesbury left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Thanks @eendebakpt. The check that ob_ref_shared is entirely zero is correct as you wrote it. We don't want non-zero flags in this case as that could allow another thread to concurrently incref the object in some circumstances.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Include/internal/pycore_object.h Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Include/internal/pycore_object.h Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Lib/test/test_free_threading/test_zip.py Outdated
Comment on lines +34 to +35
_ = [t.start() for t in worker_threads]
_ = [t.join() for t in worker_threads]

@colesbury colesbury Aug 27, 2024

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

The preferred style is to use for loops instead of using list comprehensions for side effects.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/test/test_free_threading/test_zip.py
Comment on lines +19 to +21
number_of_threads = 8
number_of_iterations = 40
n = 40_000

@colesbury colesbury Aug 27, 2024

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

We run lots of unit tests in CI, so they individually need to be very fast. For the free-threaded tests, we should aim for <0.1 seconds on two cores (i.e., when run with taskset -c 0-1 on Linux)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@eendebakpt eendebakpt Aug 27, 2024

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

On my system (windows) the test is 0.07 seconds for the free-threading build. I will reduce the number of threads and iterations a bit so it is even faster.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

colesbury reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
eendebakpt and others added 3 commits August 27, 2024 20:41
@eendebakpt @colesbury
Apply suggestions from code review
4120b51
Co-authored-by: Sam Gross <[email protected]>
@eendebakpt
review comments
cc3e3cb
@eendebakpt
resolve merge issue
29b39d2
colesbury
colesbury approved these changes Aug 27, 2024
View reviewed changes
@bedevere-app bedevere-app Bot added awaiting merge and removed awaiting review labels Aug 27, 2024
@colesbury
colesbury merged commit 7e38e67 into python:main Aug 27, 2024
@bedevere-app bedevere-app Bot removed the awaiting merge label Aug 27, 2024
@colesbury

colesbury commented Aug 27, 2024

Copy link
Copy Markdown
Contributor

Thanks for the fix @eendebakpt!

There's maybe a dozen or so similar patterns in CPython and has_unique_reference in dictobject.c. Would you be interested in updating them to use _PyObject_IsUniquelyReferenced?

I searched for the regex Py_REFCNT.* == 1, but I probably wouldn't change the matching assert() statements.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@eendebakpt

eendebakpt commented Aug 27, 2024

Copy link
Copy Markdown
Contributor Author

@colesbury Thanks for the guidance here! I was indeed planning on addressing some of the similar patterns. I'll open an new issue for this.

colesbury reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@scoder scoder mentioned this pull request Aug 24, 2025
Support freethreading Python lxml/lxml#477
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@Eclips4 Eclips4 Eclips4 left review comments
@colesbury colesbury colesbury approved these changes
@ericsnowcurrently ericsnowcurrently Awaiting requested review from ericsnowcurrently ericsnowcurrently is a code owner

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

3 participants

@eendebakpt @colesbury @Eclips4
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.