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