Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixbug threading local in coroutine #120

Merged
merged 5 commits into from
Aug 21, 2019

Conversation

NoneGG
Copy link
Owner

@NoneGG NoneGG commented Aug 18, 2019

Description

New: use contextvars instead of threading local in case of the safety of thread local mechanism being broken by coroutines

related issue #119

@NoneGG NoneGG merged commit 613dc13 into master Aug 21, 2019
@@ -77,8 +78,7 @@ def __init__(self, redis, name, timeout=None, sleep=0.1,
self.blocking = blocking
self.blocking_timeout = blocking_timeout
self.thread_local = bool(thread_local)
self.local = threading.local() if self.thread_local else dummy()
self.local.token = None
self.local = contextvars.ContextVar('token', default=None) if self.thread_local else dummy()
Copy link

Choose a reason for hiding this comment

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

The documentation for contextvars has the following disclaimer:

Important: Context Variables should be created at the top module level and never in closures. Context objects hold strong references to context variables which prevents context variables from being properly garbage collected.

Declaring the context variable in the __init__ method may result in a memory leak if my understanding is correct. I propose to declare it outside of the class definition. For example:

token_var = contextvars.ContextVar('token', default=None)


class Lock:
  def __init__(...):
  self.local = token_var if self.thread_local else dummy()
  ...

Choose a reason for hiding this comment

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

On second thought, moving the contextvar definition to the module level will cause tokens to bleed between lock instances created by the same co-routine. That's a bad idea. Sorry, you can ignore my proposal.

Copy link
Owner Author

Choose a reason for hiding this comment

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

On second thought, moving the contextvar definition to the module level will cause tokens to bleed between lock instances created by the same co-routine. That's a bad idea. Sorry, you can ignore my proposal.

Sorry, github didn't send me a msg and i saw your code review so late.

return is_error_raised

results = await asyncio.gather(coro(lock), coro(lock))
assert not (results[0] and results[1])

Choose a reason for hiding this comment

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

This assertion fails when I run this test locally. I believe the assertion is incorrect.

Both tasks/coroutines sleep for longer than the lifetime of the lock. As a consequence, both will encounter a LockError when attempting to release the lock. Hence, the correct assertion would be assert (result[0] and result[1])

Copy link
Owner Author

@NoneGG NoneGG Dec 7, 2019

Choose a reason for hiding this comment

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

@eirikur-grid

This assertion fails when I run this test locally. I believe the assertion is incorrect.

Both tasks/coroutines sleep for longer than the lifetime of the lock. As a consequence, both will encounter a LockError when attempting to release the lock. Hence, the correct assertion would be assert (result[0] and result[1])

I think you are right, the test result is random which is not appropriate

@NoneGG NoneGG deleted the fixbug-threading-local-in-coroutine branch December 7, 2019 16:52
NoneGG added a commit that referenced this pull request Dec 7, 2019
changes:

    * Fixbug: parsing stream messgae with empty payload will cause error(#116)

    * Fixbug: Let ClusterConnectionPool handle skip_full_coverage_check (#118)

    * New: threading local issue in coroutine, use contextvars instead of threading local in case of the safety of thread local mechanism being broken by coroutine (#120)

    * New: support Python 3.8
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.

None yet

2 participants