Flask解析(一):Local、LocalStak、LocalProxy

Local is what?

Whether you come into contact with is threading.Local or werkzeug.Local, they represent a variable - each thread its own global variables.


 

Global variables, generally located in the process heap. All threads of a process can access the same global variable, because they share the address space of the process, so each thread can access, it also poses a problem, if multiple threads access the same variable, this will read and write variables cause unpredictable results, so usually we use locks or other synchronization mechanisms to control access to shared variables between threads. Of course, this is not the concern of the local paper.

Coming back to Local, we mentioned that Local is the thread at the beginning of their global variables. The so-called thread of their own, that is to say the "global variables" only has access to its own thread, for other thread is not visible. How to understand this definition? Let's look at a scenario: A complete processing function parameters A, function B to A handler treated parameter A, then it is imperative function A parameter passed to the function B. A If the C function must then deal with the parameters of it, it should function D? Then the parameter A will continue to be passed between these functions, but also declared good parameter in advance when these functions of life. One can imagine that if there are parameters to be passed between the function, the function will become very complicated, very complicated function call. There is no easy way to do it?

In fact, we passed between function parameters, in order to make this parameter are required for visual function, then it will turn into a global variable you do not have to? But to become global variables, other threads will have access to my global variables may change its value, it is not the intention of this thread, I just want a monopoly it. At this point, we need a variable for this thread is concerned, it should be a global variable, in terms of the process for the other thread, it looks like a local variable. This is the kind of scenario the use of Local, Local is one such variable.

If you define a Local in the global domain, then this is not really a local global variable, each thread access the variable, this thread actually get the corresponding Local. How to achieve this effect? Actually very simple, Local itself is not a variable, it also contains a number of operations. You can interpret it this way, each process has a global dictionary, each thread has its own thread ID itself, all the threads of a process can access the global dictionary, then they put their thread ID as a key dictionary, the something needs to be stored as a value, each thread can only access the dictionary by their own key, then the value itself is equivalent to a global variable thread exclusive it! is not it? Each thread strange to take something of their own, a global thing, which is equivalent to an internal thread of a global variable. Specific code implementation differ, but generally this idea.

class Local(object):
    __slots__ = ('__storage__', '__ident_func__')
 
    def __init__(self):
        object .__ setattr __ (self, '__storage__', {}) # global dictionary storing things
        object .__ setattr __ (self, '__ident_func__', get_ident) # key for each thread
 
    def __iter__(self):
        return iter(self.__storage__.items())
 
    def __call__(self, proxy):
        """Create a proxy for a name."""
        return LocalProxy (self, proxy) # here to return a LocalProxy objects, LocalProxy is a proxy, the proxy Local object.
 
    def __release_local__(self):
        self.__storage__.pop(self.__ident_func__(), None)
 
    def __getattr__(self, name):
        try:
            return self.__storage__[self.__ident_func__()][name]
        except KeyError:
            raise AttributeError(name)
 
    def __setattr__(self, name, value):
        ident = self.__ident_func__()
        storage = self.__storage__
        try:
            storage[ident][name] = value
        except KeyError:
            storage[ident] = {name: value}
 
    def __delattr__(self, name):
        try:
            del self.__storage__[self.__ident_func__()][name]
        except KeyError:
            raise AttributeError(name)

  

Local how to use?

Pseudo code

local = Local()
local.request = "i am a request"
local.response = "i am a response"

def work():
    local.request = xxxx # Each thread will only have access to their own request and response
    local.response = xxxx # even change response, just change the value of this thread

if __name__ == "__main__":
    for i in range(10):
        Thread(target=work).start() 

 

By declaring a global Local object, and then access the object's attributes like access to the same value you want to keep. You can understand, Local equivalent of a dictionary, I want to define yourself by key to access the value I need that call local.key to get the value. Such use is very awkward, obviously I'm a defined value, they become like access an object's attributes, to write very strange, sometimes not well understood. You can not be defined as a global variable as a Local variable direct use of it?

 

# I want this effect
request = "i am a request"
response = "i am a response"

 

Local __call__ method of doing it is using __call__ method, we can make become a Local looks like a global variable.

 

# You only need to call __call__ method Local object
local = Local()
local.request = "i am a request"
my_request = local ( "request") # Note that this requires the incoming string coincides save the above 
my_request # "i am a request"

  

my_request now equivalent to local.request, compared to local.request, my_request is not look more like a global variable? But remember, it is a "thread unique global variables."

 

What LocalProxy that?

local equivalent of a dictionary, local.x of x corresponds key, and the key LocalProxy this escrow and local, we just visit LocaProxy itself, it is automatically used to get the key to the value found in local dictionary, returned to us, this is the agent (proxy)


 

my_request actually a LocalProxy, direct access my_request, it is a "i am a request" string. We mentioned Local objects can local.xxx = value to the local store I need global variables, such as local objects look like a dictionary that can store any value. But every time we want to get the value too much trouble, we need an object to help us complete this repetitive action, the key to it, bring it to the dictionary, I just access it through local.xxx, check it through the key value to the dictionary, then the value is returned to me. This way it is for me like a stored value itself. This is the agent.

 

LocalProxy principle is such that it did help us find methods to Local values, so when we want to store local.xxx "xxx" This is the key to open the local agency to tell, then tell the local agency itself, so LocalProxy will have a key, and you want to open the door, naturally he can stuff inside the door back to us. From this point of view, Local itself can also be seen as a proxy, that proxy is a thread of global variables, and it holds the key is the id of the thread, it will pass the id to the global dict find this thread global variables, and then returned to us.


class LocalProxy(object): __slots__ = ('__local', '__dict__', '__name__', '__wrapped__') def __init__(self, local, name=None): object .__ setattr __ (self, '_LocalProxy__local', local) # door to be opened object.__setattr__(self, '__name__', name)         # 钥匙 if callable(local) and not hasattr(local, '__release_local__'): # "local" is a callable that is not an instance of Local or # LocalManager: mark it as a wrapped function. object.__setattr__(self, '__wrapped__', local) def _get_current_object(self): """Return the current object. This is useful if you want the real object behind the proxy at a time for performance reasons or because you want to pass the object into a different context. """ if not hasattr(self.__local, '__release_local__'): return self.__local() try: return getattr (self .__ local, self .__ name__) # get value by key (name) to the dictionary (local) in except AttributeError: raise RuntimeError('no object bound to %s' % self.__name__) @property def __dict__(self): try: return self._get_current_object().__dict__ except RuntimeError: raise AttributeError('__dict__') def __repr__(self): try: obj = self._get_current_object() except RuntimeError: return '<%s unbound>' % self.__class__.__name__ return repr(obj) def __bool__(self): try: return bool(self._get_current_object()) except RuntimeError: return False def __unicode__(self): try: return unicode(self._get_current_object()) # noqa except RuntimeError: return repr(self) def __dir__(self): try: return dir(self._get_current_object()) except RuntimeError: return [] def __getattr__(self, name): if name == '__members__': return dir(self._get_current_object()) return getattr (self._get_current_object (), name) # through the key (name) to the dictionary (local) to go find a real value, and returns def __setitem__(self, key, value): self._get_current_object()[key] = value def __delitem__(self, key): del self._get_current_object()[key] if PY2: __getslice__ = lambda x, i, j: x._get_current_object()[i:j] def __setslice__(self, i, j, seq): self._get_current_object()[i:j] = seq def __delslice__(self, i, j): del self._get_current_object()[i:j] __setattr__ = lambda x, n, v: setattr(x._get_current_object(), n, v) __delattr__ = lambda x, n: delattr(x._get_current_object(), n)

 LocalProxy There are many methods that are some of the common methods LocalProxy itself to achieve, these methods are not a call to itself, but a call to the agent value.

We can not call the Local __call__ method of construction LocalProxy, can be a LocalProxy directly by the constructor function LocalProxy, in essence, is the same.

local = Local()
local.request = "request"
my_request = LocalProxy (local, "request") # local.xxx and the second argument to the same xxx

  

What LocalStack that?

Local LocalStack and the same, just like a Local dictionary. LocalStack is a stack, not the same way to store data. It can be considered a unique global thread stack. Use it without worrying about interference by other threads of the process.

class LocalStack(object):
    def __init__(self):
        self._local = Local()
 
    def __release_local__(self):
        self._local.__release_local__()
 
    def _get__ident_func__(self):
        return self._local.__ident_func__
 
    def _set__ident_func__(self, value):
        object.__setattr__(self._local, '__ident_func__', value)
    __ident_func__ = property(_get__ident_func__, _set__ident_func__)
    del _get__ident_func__, _set__ident_func__
 
    def __call__(self):
        def _lookup():
            rv = self.top
            if rv is None:
                raise RuntimeError('object unbound')
            return rv
        return LocalProxy(_lookup)
 
    def push(self, obj):
        """Pushes a new item to the stack"""
        rv = getattr(self._local, 'stack', None)
        if rv is None:
            self._local.stack = rv = []
        rv.append(obj)
        return rv
 
    def pop(self):
        """Removes the topmost item from the stack, will return the
        old value or `None` if the stack was already empty.
        """
        stack = getattr(self._local, 'stack', None)
        if stack is None:
            return None
        elif only (stack) == 1:
            release_local(self._local)
            return stack[-1]
        else:
            return stack.pop()
 
    @property
    def top(self):
        """The topmost item on the stack.  If the stack is empty,
        `None` is returned.
        """
        try:
            return self._local.stack[-1]
        except (AttributeError, IndexError):
            return None

 

Local differences and thread-safe

Local does not mean that the thread-safe (Thread-Safe), thread safety is more emphasis on synchronization mechanisms when multiple threads access the same global variable, and when the thread exclusive global variables Local representatives are concerned for other threads not visible, so there is the problem of insecurity thread safety does not exist. Local forever it will be operating in this thread, so if you simply wanted a definition, it is thread-safe.

 

Guess you like

Origin www.cnblogs.com/flowell/p/local_local_proxy_local_stack.html