Python Network and concurrent programming 11 threading Introduction to local() function

threading.local()

threading. The local () method allows each thread to have its own independent data, which cannot be accessed by other threads.

As shown in the figure:

Or use another more vivid metaphor, which is more appropriate. Compare a process to a company, the threads under the process to the employees of the company, and threading Local () is compared to the company's lockers. Each employee has a separate cabinet, and each employee can only access his own cabinet.

As shown in the figure:

So what does this thing do? For example, when you use Xunlei for multi-threaded download, the download progress of each thread is different, so how to store the download progress is particularly important.

Data storage must be convenient for data retrieval. If the storage structure is well done, the speed of searching and retrieving data will be faster.

threading. In fact, the design idea of local () is also reflected in the context management mechanism of flash framework. The two are basically the same, so now we understand threading After the principle of local (), it will be easy to read the source code of flash framework.

Basic use

Here are the basic usage steps:

  • Locker = threading local()
  • Use lockers under threads Item name = item. Only this thread can get the item in the future
  • When obtaining or using, directly use the lockers The item name is enough. If the item to be obtained is not stored by this thread, an exception will be thrown

Example case:

import threading


def jack(article):
    locker.rose = article
    print(locker.rose)  # Normal removal
    print(locker.food)  # Throw exception


def ken(article):
    locker.food = article
    print(locker.food)  # Normal removal
    print(locker.rose)  # Throw exception


if __name__ == "__main__":
    locker = threading.local()
    jackTask = threading.Thread(target=jack, args=("rose",))
    kenTask = threading.Thread(target=ken, args=("food",))
    jackTask.start()
    kenTask.start()

# rose
# AttributeError: '_thread._local' object has no attribute 'food'

# food
# AttributeError: '_thread._local' object has no attribute 'rose'

Principle analysis

We can create a global dictionary to achieve similar functions. The dictionary format is as follows:

locker = {
    "thread  ID" : {"Item name" : "Article itself"},
    "thread  ID" : {"Item name" : "Article itself"},
    "thread  ID" : {"Item name" : "Article itself"},
}

As follows:

import threading


def task(article):
    thId = threading.get_ident()
    
    # Start storing things
    locker[thId] = {
        "rose": article
    }
    
    # Take something out
    print(locker[thId]["rose"])


if __name__ == "__main__":
    locker = {}
    subThreadIns = threading.Thread(target=task, args=("rose",))
    subThreadIns.start()

# rose

Code optimization

Is it particularly troublesome to access things like this? So we can define a class to make the operation of this locker easier.

As follows:

import threading


class Locker:
    locker = {}

    def __getattr__(self, name):
        """When trying to use.This method is triggered when an object property is accessed and cannot be found"""
        ident = threading.get_ident()
        return __class__.locker[ident][name]

    def __setattr__(self, name, value):
        """When trying to use.This method is triggered when an object property is modified or added"""
        ident = threading.get_ident()

        if ident not in __class__.locker:
            __class__.locker[ident] = {}

        __class__.locker[ident].update({name: value})


def task(article):
    # Start storing things
    locker.rose = article
    print(locker.rose)


if __name__ == "__main__":
    locker = Locker()
    subThreadIns = threading.Thread(target=task, args=("rose",))
    subThreadIns.start()

# rose

Added by TheStalker on Fri, 21 Jan 2022 08:24:53 +0200