Python 我应该对只存在于{class,method}中的变量使用线程本地存储吗?

Python 我应该对只存在于{class,method}中的变量使用线程本地存储吗?,python,concurrency,namespaces,multithreading,Python,Concurrency,Namespaces,Multithreading,我正在用Python的Queue.Queue类实现一个相对简单的线程池。我有一个producer类,它包含队列实例和一些方便的方法,还有一个consumer类,它是threading.Thread的子类。我根据一个整数为池中想要的每个线程实例化该对象(“工作线程”,我认为它们被调用) 每个工作线程从队列中取出标志、数据,使用自己的数据库连接对其进行处理,并将行的GUID放在列表中,以便生产者类知道作业何时完成 虽然我知道其他模块实现了我正在编写的功能,但我编写此代码的原因是为了更好地理解Pyth

我正在用Python的
Queue.Queue
类实现一个相对简单的线程池。我有一个producer类,它包含
队列
实例和一些方便的方法,还有一个consumer类,它是
threading.Thread
的子类。我根据一个整数为池中想要的每个线程实例化该对象(“工作线程”,我认为它们被调用)

每个工作线程从队列中取出
标志、数据
,使用自己的数据库连接对其进行处理,并将行的GUID放在列表中,以便生产者类知道作业何时完成

虽然我知道其他模块实现了我正在编写的功能,但我编写此代码的原因是为了更好地理解Python线程是如何工作的。这就引出了我的问题

如果我在函数的名称空间或类的
\uuu dict\uuu
对象中存储任何内容,它是否是线程安全的

class Consumer(threading.Thread):
    def __init__(self, producer, db_filename):
        self.producer = producer
        self.conn = sqlite3.connect(db_filename)  # Is this var thread safe?
    def run(self):
        flag, data = self.producer.queue.get()

        while flag != 'stop':
            # Do stuff with data; Is `data` thread safe?
我认为两者都是线程安全的,以下是我的基本原理:

  • 每次实例化一个类时,都会创建一个新的
    \uuu dict\uuu
    。在我上面概述的场景下,我认为任何其他对象都不会引用这个对象。(现在,如果我使用
    join()
    功能,情况可能会变得更复杂,但我没有…)
  • 每次调用函数时,它都会创建自己的名称空间,该名称空间在函数的生命周期内一直存在。我没有将任何变量
    设置为全局的
    ,因此我不理解任何其他对象如何引用函数变量
在某种程度上解决了我的问题,但对我来说还是有点抽象


提前感谢您为我澄清此事。

您说得对;这是线程安全的。局部变量(您称之为“函数名称空间”)始终是线程安全的,因为只有执行函数的线程才能访问它们。只要实例不跨线程共享,实例属性就是线程安全的。由于consumer类继承自Thread,它的实例肯定不会在线程之间共享


这里唯一的“风险”是数据对象的价值:理论上,生产者可能会在将数据对象放入队列后保留该数据对象,并且(如果数据对象本身是可变的,请确保您理解“可变”的含义)可能会在消费者使用时更改该对象。如果生产者在将数据对象放入队列后将其单独保留,则这是线程安全的。

我认为您的假设总体上是正确的,在您的情况下,您很可能是正确的

然而,要判断某个东西是否是线程安全的要稍微困难一些,然后你说

调用例如
self.conn=sqlite3.connect(db_filename)
可能不是,因为sqlite3模块可能共享某些状态,调用该函数可能会产生一些副作用。然而,我怀疑情况是否如此,像你一样,我假设它产生了一个全新的变量

问题不仅仅在于全局变量,从外部作用域获取可变变量也是一个问题

所以数据在

flag, data = self.producer.queue.get()

可能是线程安全的,也可能不是线程安全的,这取决于数据最初生成的位置。然而,我假设这些数据将由独立的(最好是不可变的)信息组成。因此,如果是这种情况,那么所有数据都应该是线程安全的。

要使数据线程安全,请在将数据放入队列之前使用copy.deepcopy()创建数据的新副本。然后,生产者可以在下一个循环中修改数据,而无需在到达之前修改消费者副本