我很难搞清楚如何制作一个同步的Python对象。我有一个名为Observation的类和一个名为Variable的类,基本上看起来像(代码被简化以显示本质):
class Observation:
def __init__(self, date, time_unit, id, meta):
self.date = date
self.time_unit = time_unit
self.id = id
self.count = 0
self.data = 0
def add(self, value):
if isinstance(value, list):
if self.count == 0:
self.data = []
self.data.append(value)
else:
self.data += value
self.count += 1
class Variable:
def __init__(self, name, time_unit, lock):
self.name = name
self.lock = lock
self.obs = {}
self.time_unit = time_unit
def get_observation(self, id, date, meta):
self.lock.acquire()
try:
obs = self.obs.get(id, Observation(date, self.time_unit, id, meta))
self.obs[id] = obs
finally:
self.lock.release()
return obs
def add(self, date, value, meta={}):
self.lock.acquire()
try:
obs = self.get_observation(id, date, meta)
obs.add(value)
self.obs[id] = obs
finally:
self.lock.release()
这是我设置多处理部分的方法: plugin =在其他地方定义的函数 tasks = JoinableQueue() result = JoinableQueue() mgr =经理() lock = mgr.RLock() var = Variable('foobar','year',lock)
for person in persons:
tasks.put(Task(plugin, var, person))
代码应如何工作的示例:
我有一个名为var的Variable实例,我想在var:
中添加一个观察today = datetime.datetime.today()
var.add(today, 1)
因此,Variable的add函数会查看是否已存在该日期的观察,如果确实存在,则返回该观察,否则会创建一个新的Observation实例。通过调用obs.add(value)添加了比实际值更多的观察值。我主要担心的是,我想确保不同的进程不会在同一个日期创建多个Observation实例,这就是我锁定它的原因。
创建一个Variable实例,并使用多处理库在不同进程之间共享,并且是大量Observation实例的容器。上面的代码不起作用,我收到错误:
RuntimeError:仅应锁定对象 在进程之间共享 继承
但是,如果我在启动不同进程之前实例化一个Lock对象并将其提供给Variable的构造函数,那么似乎我得到一个竞争条件,因为所有进程似乎都在等待彼此。
最终目标是不同的进程可以更新对象变量中的obs变量。我需要这是线程安全的,因为我不只是修改字典,而是添加新元素和增加现有变量。 obs变量是一个包含一堆Observation实例的字典。
如何在众多多处理进程之间共享一个Variable变量实例的同步?非常感谢您的认知盈余!
更新1:
*我正在使用多处理锁,我已更改源代码以显示此信息
*我已更改标题以更准确地捕捉问题
*我已经用同步替换了theadsafe,我把两个术语混淆了。
感谢Dmitry Dvoinikov指出我!
我仍然不确定的一个问题是我在哪里实例化Lock?这应该发生在类中还是在初始化多进程并将其作为参数提供之前?答案:应该在课外发生。
更新2:
*我通过在类定义之外移动Lock的初始化并使用管理器来修复'锁定对象只应通过继承在进程之间共享'错误。
*最后的问题,现在一切正常,除了看起来当我把我的变量实例放入队列然后它没有得到更新,每次我从队列中得到它它不包含我在上一次迭代中添加的观察。这是唯一令我困惑的事情:(
更新3:
最后的解决方案是将var.obs字典设置为mgr.dict()的实例,然后设置自定义序列化程序。快乐的tho与那些正在努力解决这个问题的人分享代码。
答案 0 :(得分:3)
您所说的不是线程安全,而是关于单独进程之间的同步,而这是完全不同的事情。无论如何,要开始
不同的进程可以更新对象变量中的obs变量。
意味着变量位于共享内存中,您必须在那里显式存储对象,没有任何魔法可以使本地实例对于单独的进程可见。这里:
可以使用Value或Array
将数据存储在共享内存映射中
然后,您的代码段缺少重要的导入部分。无法判断您是否实例化了正确的多处理。锁定,而不是多线程。锁定。您的代码不会显示您创建流程和传递数据的方式。
因此,我建议您了解线程和进程之间的区别,是否真的需要一个包含多个进程的应用程序的共享内存模型并检查spec。