叽叽喳喳,嘻嘻哈哈

导航

类 线程安全变量

众所周知,Django有ORM和信号,每次通过ORM对数据库中的记录进行修改,都会触发一些信号(当然还有其他情况也会触发信号,不止是修改表).在实际工作中有这样一种需求,我们需要记录哪个人对哪些记录进行了哪些修改。如果是单线程的话,就很简单了,使用request_started或者request_finished信号即可提取出 当前请求的用户。然而实际上,一个服务不可能是单线程的,那么多线程情况下,依旧使用上面两个信号,多个线程修改表(也就是操作ORM中的类),用户肯定是不同的,那么谁又能保证某个用户就是我们想要记录的客户呢?这个时候,就需要确保类中的某个变量是线程安全的。

# pylint:disable-all
import threading
from time import sleep


class Test(object):
    name = 'unknown'
    thread = threading.local()   # 得到的是一个 <_thread._local object at 0x7f1cb57ecf10>

    def say(self):
        print('my name is: {}'.format(self.name))
        print('my thread name is: {}'.format(self.thread.name))


def t(name):
    print('set name:{}'.format(name))  
    Test.name = name 
    Test.thread.name = name
    sleep(3)
    Test().say()


def main():
    pools = []
    for idx in range(2):
        pools.append(threading.Thread(target=t, args=('thread{}'.format(idx),)))   # 开启两个线程
 
    [x.start() for x in pools]   # 分别启动两个线程(就粗略的认为它是启动吧,忽略run方法)
    [x.join() for x in pools]   # 主线程等待两个子线程的结束


if __name__ == '__main__':
    main()
#_______________________________________________________________________________________#
# set name:thread0   #  第一个线程设置 name 和 thread.name 名为 thread0
# set name:thread1  #  第二个线程设置 name 和 thread.name为 thread1
#...  等待 3s
# my name is: thread1    # 第一个线程的 name 变为了 thread1 
# my thread name is: thread0  #  第一个线程 thread.name 是 thread0
# my name is: thread1  # 第二个线程的 name 名为  thread1
# my thread name is: thread1 第二个线程的 thread.name 名为  thread1

从上面的打印信息来看,经过多个线程的操作,类的 name 变量发生了变化,而 thread.name 保持了不变。

那么如何在 ORM 中修改呢?


class RuleChangeRecord(models.Model):

    thread = threading.local()

    rucr_id = models.AutoField(primary_key=True)
    rucr_create_time = models.DateTimeField(auto_now_add=True)
    rucr_modify_time = models.DateTimeField(auto_now=True)
    rucr_user = models.CharField(max_length=255, **blank_null)
    rucr_action = models.CharField(max_length=20, choices=consts.ACTION_TYPE_ENUM)
    rucr_table_name = models.CharField(max_length=255)
    rucr_entry_id = models.IntegerField()
    rucr_field_changed = models.TextField(**blank_null)
    rucr_old = models.TextField(**blank_null)
    rucr_new = models.TextField(**blank_null)

 
    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        self.rucr_user = getattr(self.thread, 'user', None)
        return super(RuleChangeRecord, self).save(force_insert=force_insert, force_update=force_update,
                                                               using=using, update_fields=update_fields)

下面是关于 threading.local()更好,更详细的讲解:
深入理解Python中的ThreadLocal变量(上)
深入理解Python中的ThreadLocal变量(中)
深入理解Python中的ThreadLocal变量(下)

posted on 2018-01-30 10:25  叽叽喳喳,嘻嘻哈哈  阅读(165)  评论(0编辑  收藏  举报