Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-112075: Iterating a dict shouldn't require locks#115108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
DinoV merged 7 commits intopython:mainfromDinoV:nogil_dict_iter_threadsafe
Feb 22, 2024

Conversation

@DinoV
Copy link
Contributor

@DinoVDinoV commentedFeb 6, 2024
edited
Loading

Makes iteration of a dict be lock free for the forward iteration case.

Handles races against the dict as well as allowing the iterator to be used from multiple threads simultaneously.

Includes some of the shared object marking from#115109

@DinoVDinoVforce-pushed thenogil_dict_iter_threadsafe branch 2 times, most recently from1266799 to8d3080bCompareFebruary 6, 2024 22:47
@DinoVDinoV changed the titlegh-112075: Accessing a single element should optimistically avoid lockinggh-112075: Iterating a dict shouldn't require locksFeb 6, 2024
@DinoVDinoVforce-pushed thenogil_dict_iter_threadsafe branch from8d3080b tobf395f6CompareFebruary 6, 2024 22:54
@DinoVDinoVforce-pushed thenogil_dict_iter_threadsafe branch 3 times, most recently from2b2e75a to0dd1a06CompareFebruary 7, 2024 00:14
@DinoVDinoV marked this pull request as ready for reviewFebruary 7, 2024 00:48
@DinoVDinoV requested a review fromcolesburyFebruary 7, 2024 20:39
Copy link
Contributor

@colesburycolesbury left a comment
edited
Loading

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 avoid expensive atomic operations, like atomic compare exchange and atomic increments, as well as avoiding locking.

This means giving up some atomicity for list and dict iterators compared to the GIL behavior. We should still avoid crashes/memory corruption, but I think it's okay for concurrent calls tonext(it)on the same iterator object to return the same object. These iterators are almost always used by only a single thread and the performance cost of making the next atomic is relatively high.

See#114843 for the list iterator changes.

@DinoV
Copy link
ContributorAuthor

I think we want to avoid expensive atomic operations, like atomic compare exchange and atomic increments, as well as avoiding locking.

This means giving up some atomicity for list and dict iterators compared to the GIL behavior. We should still avoid crashes/memory corruption, but I think it's okay for concurrent calls tonext(it)on the same iterator object to return the same object. These iterators are almost always used by only a single thread and the performance cost of making the next atomic is relatively high.

I was worried some crazy person might be using these things to distribute work across threads :P. I'm happy to make relax the guarantees and see how that goes. I suppose if that ever becomes an issue we can deal with it then :)

@DinoVDinoVforce-pushed thenogil_dict_iter_threadsafe branch from0dd1a06 to3c03084CompareFebruary 16, 2024 00:43
Comment on lines 4539 to 4541
#endif

#ifndefPy_GIL_DISABLED
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
#endif
#ifndefPy_GIL_DISABLED
#else/* Py_GIL_DISABLED */

DinoV reacted with thumbs up emoji
returnNULL;
}

#endif
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
#endif
#endif/* Py_GIL_DISABLED */

Copy link
Contributor

@colesburycolesbury left a comment

Choose a reason for hiding this comment

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

A few code style comments below

Comment on lines 5034 to 5434
#ifdefPy_GIL_DISABLED
if (has_unique_reference(result)) {
#else
if (Py_REFCNT(result)==1) {
#endif
Copy link
Contributor

Choose a reason for hiding this comment

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

has_unique_reference already has special cases forPy_GIL_DISABLED and the default build:

Suggested change
#ifdefPy_GIL_DISABLED
if (has_unique_reference(result)) {
#else
if (Py_REFCNT(result)==1) {
#endif
if (has_unique_reference(result)) {

Comment on lines 4936 to 5333
if (values==NULL)
gotoconcurrent_modification;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the preferred style is to always include braces in new C code

Comment on lines 4940 to 5338
if (i >=used)
gotofail;
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here

// Even though we hold the lock here we may still lose a race against
// a lock-free iterator, therefore we may end up retrying our iteration.
retry:
start_pos=i=_Py_atomic_load_ssize_relaxed(&di->di_pos);
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe use the wrappers frompycore_pyatomic_ft_wrappers.h to reduce the number of#ifdef statements.

@DinoVDinoVforce-pushed thenogil_dict_iter_threadsafe branch 3 times, most recently frome2a13a2 to0941e62CompareFebruary 21, 2024 22:06
Copy link
Contributor

@colesburycolesbury left a comment

Choose a reason for hiding this comment

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

This looks good, but I think it'd be better ifacquire_key_value follows the-1/0 convention. The comment aboveacquire_key_value would need to be updated too.

Comment on lines +5278 to +5279
staticint
acquire_key_value(PyObject**key_loc,PyObject*value,PyObject**value_loc,
Copy link
Contributor

Choose a reason for hiding this comment

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

Also here:-1 for error and0 for success

DinoV reacted with thumbs up emoji
@DinoVDinoVforce-pushed thenogil_dict_iter_threadsafe branch from0941e62 toa1d7718CompareFebruary 22, 2024 18:32
@DinoVDinoV merged commit1002fbe intopython:mainFeb 22, 2024
woodruffw pushed a commit to woodruffw-forks/cpython that referenced this pull requestMar 4, 2024
)Makes iteration of a dict be lock free for the forward iteration case.
diegorusso pushed a commit to diegorusso/cpython that referenced this pull requestApr 17, 2024
)Makes iteration of a dict be lock free for the forward iteration case.
LukasWoodtli pushed a commit to LukasWoodtli/cpython that referenced this pull requestJan 22, 2025
)Makes iteration of a dict be lock free for the forward iteration case.
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@methanemethanemethane left review comments

@colesburycolesburycolesbury approved these changes

@markshannonmarkshannonAwaiting requested review from markshannonmarkshannon is a code owner

Assignees

No one assigned

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

3 participants

@DinoV@methane@colesbury

[8]ページ先頭

©2009-2025 Movatter.jp