Graham Lea
Graham Lea

Reputation: 6343

Is there any reason to use Python threading.local() rather than a ContextVar (in >= 3.7)

Python's thread-local data and ContextVars appear to achieve the same thing (while having slightly different APIs), with the only user-facing difference being that ContextVars work with async code (coroutines and asyncio), while thread-local data does not.

Is that truly the only practical difference?

Does that mean any code targeting a runtime >= 3.7 (when ContextVar was introduced) is better off using ContextVar everywhere thread-local data might have been used in the past? Or is there a reason to prefer thread-local data still? (Except for scenarios where you specifically want to associate the state with the thread rather than with the context.)

Upvotes: 14

Views: 4829

Answers (2)

Conchylicultor
Conchylicultor

Reputation: 5739

I agree with @jsbueno that the contextvar API is painful to use.

I also create some higher level wrapper to simplify the usage: https://etils.readthedocs.io/en/latest/edc.html#wrap-fields-around-contextvar

from etils import edc

@edc.dataclass
@dataclasses.dataclass
class Scope:
  is_active: edc.ContextVar[bool] = False

  @contextlib.contextmanager
  def activate(self):
    self.is_active = True
    try:
      yield
    finally:
      self.is_active = False


scope = Scope()

# Each thread/coroutine will have their own version
with scope.activate():
  ...

Upvotes: 0

jsbueno
jsbueno

Reputation: 110591

The main problem, IMO, is that the "slightly different APIs" are actually huge differences, and while thread.local is straightforward to use, ContextVars present a low-level painful(*), hard to grasp and verbose alternative.

Other than that, ContextVars seem to be the way to go.
I am working on some code to wrap around ContextVars so they can be a drop-in replacement, but the thing is not production ready yet. update: it is now published as python-extracontext and work extracontext.Contextlocal() as a drop in replacement for threading.local(), using Pythoh contextvars under the hood.

If anyone is interested, the project is paused now, lacking some refinement (docs, etc...) for a published package, but it is fully functional at: https://github.com/jsbueno/extracontext/ or simply pip install python-extracontext.

(*) Ok "painful" is maybe too subjective, but I swear it feels like that, but it might be because I do not currently have a "real world" use case needing that, and the artificial examples I use are just too artificial grasp the actual use-cases.

Upvotes: 4

Related Questions