python中构造函数/析构函数中的线程锁定/解锁
我有一个只能通过静态方法从外部访问的类。然后,这些静态方法创建类的一个对象以在方法中使用,然后返回,对象可能被销毁。该类是几个配置文件的getter/setter,现在我需要在访问配置文件时放置线程锁 由于我有几个不同的静态方法,它们都需要对所有在方法范围内创建对象的配置文件进行读/写访问,因此我考虑在对象构造函数中完成锁获取,然后在析构函数中释放 我的同事表示担心,如果发生了什么事情,可能会使类永远锁定。他还提到了python中的析构函数是如何调用垃圾收集器的,但我们都是python的新手,所以这是个未知数 这是一个合理的解决方案,还是应该锁定/解锁每个方法本身python中构造函数/析构函数中的线程锁定/解锁,python,multithreading,locking,Python,Multithreading,Locking,我有一个只能通过静态方法从外部访问的类。然后,这些静态方法创建类的一个对象以在方法中使用,然后返回,对象可能被销毁。该类是几个配置文件的getter/setter,现在我需要在访问配置文件时放置线程锁 由于我有几个不同的静态方法,它们都需要对所有在方法范围内创建对象的配置文件进行读/写访问,因此我考虑在对象构造函数中完成锁获取,然后在析构函数中释放 我的同事表示担心,如果发生了什么事情,可能会使类永远锁定。他还提到了python中的析构函数是如何调用垃圾收集器的,但我们都是python的新手,所
Class A():
rateLock = threading.RLock()
chargeLock = threading.RLock()
@staticmethod
def doZStuff():
a = A()
a.doStuff('Z')
@staticmethod
def doYStuff():
a = A()
a.doStuff('Y')
@synchronized(lock)
def doStuff(self, type):
if type == 'Z':
otherstuff()
elif type == 'B':
evenmorestuff()
甚至可以用doStuff()
而不是doZStuff()
更新
谢谢大家的回答。我面临的问题主要是因为异步访问我的模块没有意义,但这只是API的一部分。通过API访问我们的东西的团队抱怨并发性问题。所以我不需要完美的解决方案,我只是想让他们不会破坏我们的团队或回收垃圾数据。垃圾收集是正确的,所以这不是一个好主意。 查看decorator,以编写同步函数 例如: 编辑 我仍然不能100%确定您的想法,因此我的建议可能是错误的:
class A():
lockZ = threading.RLock()
lockY = threading.RLock()
@staticmethod
@synchroized(lockZ)
def doZStuff():
a = A()
a.doStuff('Z')
@staticmethod
@synchroized(lockY)
def doYStuff():
a = A()
a.doStuff('Y')
def doStuff(self, type):
if type == 'Z':
otherstuff()
elif type == 'B':
evenmorestuff()
我不知道您在哪个平台上,但是如果您需要锁定文件,那么,如果文件可用,您可能应该使用
flock()
,而不是使用自己的锁定例程
既然您提到您是python新手,我必须说,大多数情况下线程不是python中的解决方案。如果您的活动是CPU绑定的,则应该考虑使用。因为GIL没有并发执行,记得吗?(大多数情况下都是如此)。如果您的活动是I/O绑定,我想是这样的话,那么您应该考虑使用事件驱动的框架,比如。这样你就不用担心死锁了,我保证:)
使用将保证成对获取和释放(R)锁。即使with块中发生异常,也将调用释放
您可能还想考虑将锁尽可能紧密地围绕文件访问块放置,打开(…)为…
,这样锁的持有时间就不会超过需要的时间
最后,a=a()的创建和垃圾收集不会影响锁
如果(如上所述)锁是类属性(与实例属性相反)。类属性位于
A.\uu dict\uu
中,而不是A.\uu dict\uu
。因此,在对自身进行垃圾收集之前,不会对锁进行垃圾收集。在销毁对象时释放锁是有风险的,因为垃圾收集器已经提到了这一点,因为决定何时对对象调用\u del\uu()
方法完全由GC决定(通常当refcount为零时)但在某些情况下,如果有循环引用,则可能永远不会调用它,即使程序退出时也是如此
如果在类实例中处理一个特定的configfile,那么可以将线程模块中的锁对象放入其中。
这方面的一些示例代码:
from threading import Lock
class ConfigFile:
def __init__(file):
self.file = file
self.lock = Lock()
def write(self, data):
self.lock.aquire()
<do stuff with file>
self.lock.release()
# Function that uses ConfigFile object
def staticmethod():
config = ConfigFile('myconfig.conf')
config.write('some data')
来自线程导入锁
类配置文件:
定义初始化(文件):
self.file=文件
self.lock=lock()
def写入(自身、数据):
self.lock.aquire()
self.lock.release()
#使用ConfigFile对象的函数
def staticmethod():
config=ConfigFile('myconfig.conf')
config.write('some data')
您还可以在With语句中使用锁,例如:
def write(self, data):
with self.lock:
<do stuff with file>
def写入(自身、数据):
使用self.lock:
Python将为您获取并释放锁,即使在处理文件时发生错误。但是,如果您必须获取并释放构造函数和析构函数中的锁,那么您真的、真的、真的应该给您的设计另一个机会。您应该改变您的基本假设 在任何应用程序中:一个“锁”应该总是保持很短的时间-尽可能短。这意味着-在可能90%的情况下,您将以同样的方法获得锁,也将释放锁 几乎不应该有任何理由以RAII样式锁定/解锁对象。这不是它的本意;) 让我给你举个例子:你管理一些资源,这些资源可以一次从多个线程读取,但只有一个线程可以写入它们 在一个“幼稚”的实现中,每个对象都有一个锁,每当有人想对其进行写入时,您都会锁定它。当多个线程想要写入时,您可以公平地、安全地对其进行同步,但是:当线程说“写入”时,我们将暂停,直到其他线程决定释放锁
但是请理解,锁、互斥锁——所有这些原语都是为了同步源代码的几行而创建的。因此,与使锁成为可写对象的一部分不同,您只有一个真正需要锁的很短时间内的锁。您必须在界面上投入更多的时间和精力。但是,锁/互斥锁的“保持”时间决不能超过几微秒。这是一个更大项目的一部分,我只真正了解我的密码
def write(self, data):
with self.lock:
<do stuff with file>