当我们使用线程时,如果多线程同时对一个全局变量进行修改,很容易造成错误,这是我们可以利用加锁的方式,让线程一个一个进行操作

同样我们可以threading.local来实现

threading.local的使用

不使用threading.local时

from threading import Thread
from threading import local
import time
# xianglong = local()

xianglong = -1

def task(arg):
    global xianglong
    xianglong = arg
    time.sleep(2)
    print(xianglong)


for i in range(10):
    t = Thread(target=task,args=(i,))
    t.start()

输出结果

9
9
9
9
9
9
9
9
9
9

可以看到,由于所以的线程都在修改同一个全局变量,导致最后无法得到想要的结果

使用threading.loacl

from threading import Thread
from threading import local
import time
from threading import get_ident
# 特殊的对象
xianglong = local()


def task(arg):
    # 对象.val = 1/2/3/4/5
    xianglong.value = arg
    time.sleep(2) 
    print(xianglong.value)


for i in range(10):
    t = Thread(target=task,args=(i,))
    t.start()

输出结果

0
1
2
3
5
4
6
7
8
9

使用了threading.local会为每一个线程创建一个独立的空间存储变量

get_ident

我们可以通过get_ident来获取每一个线程的独特的值,类似于线程号

from threading import Thread
from threading import get_ident


def task(arg):
    print(get_ident())


for i in range(10):
    t = Thread(target=task,args=(i,))
    t.start()

输出结果

5028
6088
7340
8384
8648
3372
8752
5620
6308
4396

自己写一个类似于threading的功能

try:
    from greenlet import getcurrent as get_ident
except Exception as e:
    from threading import get_ident

from threading import Thread
import time

class Local(object):

    def __init__(self):
        object.__setattr__(self,'storage',{})

    def __setattr__(self, k, v):
        ident = get_ident()
        if ident in self.storage:
            self.storage[ident][k] = v
        else:
            self.storage[ident] = {k: v}

    def __getattr__(self, k):
        ident = get_ident()
        return self.storage[ident][k]

obj = Local()

def task(arg):
    obj.val = arg
    obj.xxx = arg
    print(obj.val)

for i in range(10):
    t = Thread(target=task,args=(i,))
    t.start()

用.给对象设置值时会调用__setattr__方法,这里我们导入时使用了try捕捉异常,先导入协程的get_ident,如果没有则导入线程的,所以我们的方法比threading.loacl多了一个实现协程的功能,不同的线程可以在obj对象的storage字典中利用自己的get_ident值为键生成对

应的值,在定义self.storage时我们调用的是父类object类的__setattr__方法,那是因为我们自己的类定义了这个方法,直接使用self.storage={}会执行自己类的__setattr__方法,会出问题

posted on 2018-04-28 08:25  Py行僧  阅读(137)  评论(0编辑  收藏  举报