zoukankan      html  css  js  c++  java
  • 十二、threading.local

    1、线程之间资源共享和threading.local

    代码:

     1 from threading import local, Thread
     2 
     3 
     4 i = None
     5 
     6 
     7 def func(num):
     8     global i
     9     i = num
    10     print(i)
    11 
    12 
    13 threads = []
    14 for i in range(10):
    15     threads.append(Thread(target=func, args=(i, )))
    16 
    17 for thread in threads:
    18     thread.start()
    19 
    20 for thread in threads:
    21     thread.join()

    输出:

     由于没有阻塞操作,导致看不出没有给数据加锁会造成什么影响,

    加入阻塞操作后的代码:

     1 from threading import local, Thread
     2 from time import sleep
     3 
     4 
     5 i = None
     6 
     7 
     8 def func(num):
     9     global i
    10     i = num
    11     sleep(2)
    12     print(i)
    13 
    14 
    15 threads = []
    16 for i in range(10):
    17     threads.append(Thread(target=func, args=(i, )))
    18 
    19 for thread in threads:
    20     thread.start()
    21 
    22 for thread in threads:
    23     thread.join()

    输出:

     由于加入阻塞操作后,所有的线程在未输入i之前,争夺资源i,使得每个线程最终输出的i都是最后一次修改的数据,

    那么有什么方法,可以使得每次在线程中访问同一个数据,但都是自己的资源,线程之间的数据相互隔离呢?

    使用threading.local,

    代码:

     1 from threading import local as Local, Thread, RLock
     2 from time import sleep
     3 
     4 
     5 i = None
     6 local = Local()
     7 
     8 
     9 def func(num):
    10     local.x = num
    11     sleep(0.3)
    12     print(local.x)
    13 
    14 
    15 threads = []
    16 for i in range(10):
    17     threads.append(Thread(target=func, args=(i, )))
    18 
    19 for thread in threads:
    20     thread.start()
    21 
    22 for thread in threads:
    23     thread.join()

    输出:

     2、threading.local原理

      threading.local是一个类,当实例化后,使用点号给对象某个属性赋值时就会调用__setattr__方法,使用点号获取某个属性值时就会调用__getattr__,

    我们可以在local对象中设置一个类似于字典的属性,每当要设置某个属性值或者访问某个属性时,就在__setattr__或__getattr__中找到对应线程存储的值(或者说为每个访问环境设置一个唯一标识符,对应访问环境中的值),

    函数实现:

     1 from threading import Thread, get_ident
     2 from time import sleep
     3 
     4 storage = {}
     5 
     6 
     7 def set(k, v):
     8     # 获取当前线程或携程的唯一标识
     9     ident = get_ident()
    10     if ident in storage:
    11         storage[ident][k] = v
    12     else:
    13         storage[ident] = {k:v}
    14 
    15 def get(k):
    16     ident = get_ident()
    17     try:
    18         res = storage[ident][k]
    19     except Exception as e:
    20         return None
    21     else:
    22         return res
    23 
    24 
    25 def func(num):
    26     set("x", num)
    27     sleep(2)
    28     print(get("x"))
    29 
    30 
    31 threads = []
    32 for i in range(10):
    33     threads.append(Thread(target=func, args=(i, )))
    34 
    35 for thread in threads:
    36     thread.start()
    37 
    38 for thread in threads:
    39     thread.join()

    输出:

     错误的类实现:

     1 from threading import Thread, get_ident
     2 from time import sleep
     3 
     4 
     5 class Local(object):
     6     def __init__(self):
     7         self.storage = {}
     8 
     9     def __setattr__(self, key, value):
    10         ident = get_ident()
    11         if ident in self.storage:
    12             self.storage[ident][key] = value
    13         else:
    14             self.storage[ident] = {key: value}
    15 
    16     def __getattr__(self, item):
    17         ident = get_ident()
    18         try:
    19             res = self.storage[ident][item]
    20         except Exception as e:
    21             return None
    22         else:
    23             return res
    24 
    25 local = Local()
    26 
    27 def func(num):
    28     local.x = num
    29     print(local.x)
    30 
    31 
    32 threads = []
    33 for i in range(10):
    34     threads.append(Thread(target=func, args=(i, )))
    35 
    36 for thread in threads:
    37     thread.start()
    38 
    39 for thread in threads:
    40     thread.join()

    报错信息:

     原因:

      不可以直接在初始化对象时,直接将对象设置storage为字典,因为当使用self.storage={}时,就会调用self.__setattr__("storage", {}),而第11行的storage属性还没有被设置,因而为NoneType类型

    正确的类实现:

     1 from threading import Thread, get_ident
     2 from time import sleep
     3 
     4 
     5 class Local(object):
     6     def __init__(self):
     7         object.__setattr__(self, "storage", {})
     8 
     9     def __setattr__(self, key, value):
    10         ident = get_ident()
    11         if ident in self.storage:
    12             self.storage[ident][key] = value
    13         else:
    14             self.storage[ident] = {key: value}
    15 
    16     def __getattr__(self, item):
    17         ident = get_ident()
    18         try:
    19             res = self.storage[ident][item]
    20         except Exception as e:
    21             return None
    22         else:
    23             return res
    24 
    25 local = Local()
    26 
    27 def func(num):
    28     local.x = num
    29     print(local.x)
    30 
    31 
    32 threads = []
    33 for i in range(10):
    34     threads.append(Thread(target=func, args=(i, )))
    35 
    36 for thread in threads:
    37     thread.start()
    38 
    39 for thread in threads:
    40     thread.join()

    输出:

  • 相关阅读:
    day3
    day2
    day1-存储
    day5-iptables
    MySQL之补充
    11.18
    11.17
    junit基础学习之-测试controller层(2)
    junit基础学习之-简介(1)
    外键和级联
  • 原文地址:https://www.cnblogs.com/loveprogramme/p/13430690.html
Copyright © 2011-2022 走看看