diff options
Diffstat (limited to 'Doc/library/threading.rst')
-rw-r--r-- | Doc/library/threading.rst | 129 |
1 files changed, 119 insertions, 10 deletions
diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst index d948493c210..249c0a5cb03 100644 --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -260,23 +260,132 @@ All of the methods described below are executed atomically. Thread-Local Data ----------------- -Thread-local data is data whose values are thread specific. To manage -thread-local data, just create an instance of :class:`local` (or a -subclass) and store attributes on it:: +Thread-local data is data whose values are thread specific. If you +have data that you want to be local to a thread, create a +:class:`local` object and use its attributes:: - mydata = threading.local() - mydata.x = 1 + >>> mydata = local() + >>> mydata.number = 42 + >>> mydata.number + 42 -The instance's values will be different for separate threads. +You can also access the :class:`local`-object's dictionary:: + + >>> mydata.__dict__ + {'number': 42} + >>> mydata.__dict__.setdefault('widgets', []) + [] + >>> mydata.widgets + [] + +If we access the data in a different thread:: + + >>> log = [] + >>> def f(): + ... items = sorted(mydata.__dict__.items()) + ... log.append(items) + ... mydata.number = 11 + ... log.append(mydata.number) + + >>> import threading + >>> thread = threading.Thread(target=f) + >>> thread.start() + >>> thread.join() + >>> log + [[], 11] + +we get different data. Furthermore, changes made in the other thread +don't affect data seen in this thread:: + + >>> mydata.number + 42 + +Of course, values you get from a :class:`local` object, including their +:attr:`~object.__dict__` attribute, are for whatever thread was current +at the time the attribute was read. For that reason, you generally +don't want to save these values across threads, as they apply only to +the thread they came from. + +You can create custom :class:`local` objects by subclassing the +:class:`local` class:: + + >>> class MyLocal(local): + ... number = 2 + ... def __init__(self, /, **kw): + ... self.__dict__.update(kw) + ... def squared(self): + ... return self.number ** 2 + +This can be useful to support default values, methods and +initialization. Note that if you define an :py:meth:`~object.__init__` +method, it will be called each time the :class:`local` object is used +in a separate thread. This is necessary to initialize each thread's +dictionary. + +Now if we create a :class:`local` object:: + + >>> mydata = MyLocal(color='red') + +we have a default number:: + + >>> mydata.number + 2 + +an initial color:: + + >>> mydata.color + 'red' + >>> del mydata.color + +And a method that operates on the data:: + + >>> mydata.squared() + 4 + +As before, we can access the data in a separate thread:: + + >>> log = [] + >>> thread = threading.Thread(target=f) + >>> thread.start() + >>> thread.join() + >>> log + [[('color', 'red')], 11] + +without affecting this thread's data:: + + >>> mydata.number + 2 + >>> mydata.color + Traceback (most recent call last): + ... + AttributeError: 'MyLocal' object has no attribute 'color' + +Note that subclasses can define :term:`__slots__`, but they are not +thread local. They are shared across threads:: + + >>> class MyLocal(local): + ... __slots__ = 'number' + + >>> mydata = MyLocal() + >>> mydata.number = 42 + >>> mydata.color = 'red' + +So, the separate thread:: + + >>> thread = threading.Thread(target=f) + >>> thread.start() + >>> thread.join() + +affects what we see:: + + >>> mydata.number + 11 .. class:: local() A class that represents thread-local data. - For more details and extensive examples, see the documentation string of the - :mod:`!_threading_local` module: :source:`Lib/_threading_local.py`. - .. _thread-objects: @@ -452,7 +561,7 @@ since it is impossible to detect the termination of alien threads. of :term:`Python finalization <interpreter shutdown>` :meth:`!join` raises a :exc:`PythonFinalizationError`. - .. versionchanged:: next + .. versionchanged:: 3.14 May raise :exc:`PythonFinalizationError`. |