Skip to content

Lockless implementation of add_callback#1876

Merged
bdarnell merged 4 commits intotornadoweb:masterfrom
pitrou:lockless_add_callback
Nov 4, 2016
Merged

Lockless implementation of add_callback#1876
bdarnell merged 4 commits intotornadoweb:masterfrom
pitrou:lockless_add_callback

Conversation

@pitrou
Copy link
Contributor

@pitrou pitrou commented Nov 3, 2016

Fixes #1874.

@pitrou
Copy link
Contributor Author

pitrou commented Nov 3, 2016

I've stress-tested this PR with the following script: https://gist.github.com/pitrou/6a89c8563599beccb1763f27951af416
(the number of added and called callbacks at the end should be the same)

@pitrou
Copy link
Contributor Author

pitrou commented Nov 3, 2016

Also see previous discussion in #1875.

f.close()
except IOError:
# Yield to another thread
time.sleep(1e-3)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this long enough to avoid the Beazley Effect in Python 2 on multicore? That is, is there a danger that this same thread will reacquire the GIL without actually letting another thread run?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unless many non-Python threads are competing for the CPU, yes. We cannot guarantee this approach will always work, but it reasonably should.

self._callbacks.append(functools.partial(
stack_context.wrap(callback), *args, **kwargs))
# If we're on the IOLoop's thread, we don't need to wake anyone.
pass
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems distracting, could you merge this explanation with the previous comment block and delete the "else" branch?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do.

@ajdavis
Copy link
Contributor

ajdavis commented Nov 3, 2016

I like this a lot and would vote for merging.

@bdarnell
Copy link
Member

bdarnell commented Nov 4, 2016

LGTM. The main purpose of the lock was to avoid unnecessary calls to the waker, but that predated the introduction of the thread.ident check. This change will make cross-thread add_callbacks slightly slower since every call will need to write to the waker, but that seems like a good tradeoff to get rid of the locking in the single-thread case.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants