• Flask上下文以及python__setattr__常见问题


    Flask上下文管理
    -threading.local对象,用于为每个线程开辟一块空间来保存它独有的值。
    -源码(request)
        -情况一:单进程单线程,基于全局变量做。
        -情况二:单进程多线程,threading.local对象。
        -情况三:单进程单线程(多协程),threading.lcoal对象做不到。
    -建议:
        -以后不支持协程:就用threading.local对象
        -支持协程:自定义类似threading.local对象
     
    线程
    通过threading.local()保护线程数据安全
     1 import threading
     2 local_values = threading.local()
     3 
     4 '''
     5 local_values = threading.local()就是起到一个锁的作用,每个线程都可以对threading.local对象进行读写,且互相不干扰。
     6 用于为每个线程开辟一块空间来保存它独有的值。
     7 '''
     8 def func(num):
     9     local_values.name=num
    10     import time
    11     time.sleep(1)
    12     print(local_values.name,threading.current_thread().name)
    13 
    14 for i in range(10):
    15     th = threading.Thread(target=func,args=(i,),name="线程是%s"%i)
    16     th.start()

     
     
    一个简单的自定义方法实现threading.local功能:
    线程
     1 import threading
     2 from _thread import get_ident
     3 '''获取线程唯一标示'''
     4 class LOCAL(object):
     5     '''
     6     通过自定义的方式实现threadlocal的功能
     7     初始化的时候定义一个字典以及线程唯一标示
     8     然后通过set设置k,v,再用get取值
     9     '''
    10     def __init__(self):
    11         self.storage = {}
    12         self.get_ident = get_ident
    13     def set(self,k,v):
    14         ident = self.get_ident()
    15         origin = self.storage.get(ident)
    16         if not origin:
    17             origin = {k:v}
    18         else:
    19             origin[k] = v
    20         self.storage[ident] = origin
    21     def get(self,k):
    22         ident = self.get_ident()
    23         origin = self.storage.get(ident)
    24         if not origin:
    25             return  None
    26         return origin.get(k,None)
    27 
    28 local_values = LOCAL()
    29 def task(num):
    30     local_values.set('name',num)
    31     import time
    32     time.sleep(1)
    33     print(local_values.get('name'), threading.current_thread().name)
    34 for i in range(10):
    35     th = threading.Thread(target=task,args=(i,),name="线程是%s"%i)
    36     th.start()
    通过安装gevent,用getcurrent的方式获取协程的唯一标示:
    以下是实现协程的单独资源管理
     1 import threading
     2 from greenlet import getcurrent as get_ident
     3 '''获取协程唯一标示,需要安装gevent,同时自动安装greenlet,通过
     4 from greenlet import getcurrent 模块判断协程唯一标示,其他代码不变'''
     5 class LOCAL(object):
     6     '''
     7     通过自定义的方式实现threadlocal的功能
     8     初始化的时候定义一个字典以及线程唯一标示
     9     然后通过set设置k,v,再用get取值
    10     '''
    11     def __init__(self):
    12         self.storage = {}
    13         self.get_ident = get_ident
    14     def set(self,k,v):
    15         ident = self.get_ident()
    16         origin = self.storage.get(ident)
    17         if not origin:
    18             origin = {k:v}
    19         else:
    20             origin[k] = v
    21         self.storage[ident] = origin
    22     def get(self,k):
    23         ident = self.get_ident()
    24         origin = self.storage.get(ident)
    25         if not origin:
    26             return  None
    27         return origin.get(k,None)
    28 
    29 local_values = LOCAL()
    30 def task(num):
    31     local_values.set('name',num)
    32     import time
    33     time.sleep(1)
    34     print(local_values.get('name'), threading.current_thread().name)
    35 for i in range(10):
    36     th = threading.Thread(target=task,args=(i,),name="线程是%s"%i)
    37     th.start()
     
     
    面向对象知识点补充
    关于__setattr__的使用以及常见问题:
     1 #扩展内容,__setattr__
     2 class Foo(object):
     3     def set(self,k,v):
     4         pass
     5     def __setattr__(self, key, value):
     6         print(key,value)
     7         pass
     8 
     9 obj = Foo()
    10 obj.set('x',123)
    11 obj.x = 123 #用__setattr__比set函数要方便许多
    12 
    13 #__setattr__方法常见的坑
    14 
    15 class Foo(object):
    16     def __init__(self):
    17         self.storage = {}
    18     def __setattr__(self, key, value):
    19         self.storage={'k1':'v1'}
    20         print(key,value)
    21     def __getattr__(self, item):
    22         print(item)
    23 
    24 
    25 obj = Foo()
    26 obj.x = 123
    27 '''
    28 当初始化的时候,self.storage,对象调用storage就会自动执行__setattr__方法,
    29 然后__setattr__方法里面又是对象调用属性,就会再执行setattr,这样就是无限递归了。
    30 为了避免这个问题需要用下面这种方式实现:
    31 '''
    32 class Foo(object):
    33     def __init__(self):
    34         object.__setattr__(self,'storage',{})
    35 
    36     def __setattr__(self, key, value):
    37         self.storage={'k1':'v1'}
    38         print(key,value)
    39 
    40     def __getattr__(self, item):
    41         print(item)
    42         return "sdf"
    43 obj = Foo()
    44 #注意如果obj.x = 123就会触发__setattr__方法,还是会出现递归的问题。
    以下为参考源码实现的方式:
     1 #源码的实现方式:
     2 import threading
     3 try:
     4     from greenlet import getcurrent as get_ident # 协程
     5 except ImportError:
     6     try:
     7         from thread import get_ident
     8     except ImportError:
     9         from _thread import get_ident # 线程
    10 
    11 
    12 class Local(object):
    13 
    14     def __init__(self):
    15         object.__setattr__(self, '__storage__', {})
    16         object.__setattr__(self, '__ident_func__', get_ident)
    17 
    18 
    19     def __getattr__(self, name):
    20         try:
    21             return self.__storage__[self.__ident_func__()][name]
    22         except KeyError:
    23             raise AttributeError(name)
    24 
    25     def __setattr__(self, name, value):
    26         ident = self.__ident_func__()
    27         storage = self.__storage__
    28         try:
    29             storage[ident][name] = value
    30         except KeyError:
    31             storage[ident] = {name: value}
    32 
    33     def __delattr__(self, name):
    34         try:
    35             del self.__storage__[self.__ident_func__()][name]
    36         except KeyError:
    37             raise AttributeError(name)
    38 
    39 
    40 local_values = Local()
    41 
    42 
    43 def task(num):
    44     local_values.name = num
    45     import time
    46     time.sleep(1)
    47     print(local_values.name, threading.current_thread().name)
    48 
    49 
    50 for i in range(20):
    51     th = threading.Thread(target=task, args=(i,),name='线程%s' % i)
    52     th.start()
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    Spring-整合MyBatis-声明式事务
    Spring-AOP
    Spring-使用注解开发
    Spring-bean的自动装配
    Spring-HelloSpring-IOC创建对象的方式
    Objective-C学习笔记2013[NSString]字符串[可变字符串中,加用app减用delete]
    C语言I博客作业04
    C语言I博客作业03
    C语言I博客作业02
    malloc/free 和 new/delete
  • 原文地址:https://www.cnblogs.com/ArmoredTitan/p/8887019.html
Copyright © 2020-2023  润新知