如何使用Python多处理创建同步对象?

时间:2011-02-16 21:43:26

标签: python synchronization thread-safety multiprocessing

我很难搞清楚如何制作一个同步的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与那些正在努力解决这个问题的人分享代码。

1 个答案:

答案 0 :(得分:3)

您所说的不是线程安全,而是关于单独进程之间的同步,而这是完全不同的事情。无论如何,要开始

  

不同的进程可以更新对象变量中的obs变量。

意味着变量位于共享内存中,您必须在那里显式存储对象,没有任何魔法可以使本地实例对于单独的进程可见。这里:

  

可以使用Value或Array

将数据存储在共享内存映射中

然后,您的代码段缺少重要的导入部分。无法判断您是否实例化了正确的多处理。锁定,而不是多线程。锁定。您的代码不会显示您创建流程和传递数据的方式。

因此,我建议您了解线程和进程之间的区别,是否真的需要一个包含多个进程的应用程序的共享内存模型并检查spec