如何在线程之间共享值并通知消费线程设置了新值

时间:2016-08-17 14:40:08

标签: python multithreading multiprocessing python-multiprocessing

对我来说,一个相当常见的情况是定期更新一个值,比如说每30秒一次。该值可在例如网站上获得。

我想取这个值(使用读者),转换它(使用变换器)并发布结果,比如在另一个网站上(发布者)。

源和目的地都可能不时无法使用,我只对新值和超时感兴趣。

我当前的方法是为我的值使用队列,为结果使用另一个队列。读者,变换器和发布者都是使用多处理的独立“线程”。

这样做的好处是,每个步骤都可以允许“挂起”一段时间,下一步可以使用带超时的get来实现一些默认操作,以防队列中没有有效的消息。

这种方法的缺点是,一旦变换器或发布者停止,我就会留下所有先前的值并导致我的队列。在最糟糕的情况下,发布者有一个不可恢复的错误,整个工具内存不足。

此问题的一种可能解决方案是将队列大小限制为1,使用非阻塞put并通过丢弃当前值并重新放置新值来处理队列完全异常。对于这样一个简单的操作,这是很多代码,并清楚地表明队列不是正确的工具。

我可以编写自己的类来获取我想要的使用多处理原语的行为,但这对我来说是一种非常常见的情况,所以我认为它也适用于其他人,我觉得应该有一个'正确'的解决方案某处。

简而言之,是否有一个带有以下接口的标准线程安全类?

class Updatable():
    def put(value):
        #store value, overwriting existing

    def get(timeout):
        #blocking, raises Exception when timeout is set and exceeded
        return value

编辑:我使用多处理的当前实现

import multiprocessing
from time import sleep

class Updatable():
    def __init__(self):
        self.manager = multiprocessing.Manager()
        self.ns = self.manager.Namespace()
        self.updated = self.manager.Event()

    def get(self, timeout=None):
        self.updated.wait(timeout)
        self.updated.clear()
        return self.ns.x

    def put(self, item):
        self.ns.x = item
        self.updated.set()


def consumer(updatable):
    print(updatable.get())  # expect 1
    sleep(1)
    print(updatable.get())  # expect "2"
    sleep(1)
    print(updatable.get())  # expect {3}, after 2 sec
    sleep(1)
    print(updatable.get())  # expect [4]
    sleep(2)
    print(updatable.get())  # expect 6
    sleep(1)

def producer():
    sleep(.5)  # make output more stable, by giving both sides 0.5 sec to process
    updatable.put(1)
    sleep(1)
    updatable.put("2")
    sleep(2)
    updatable.put({3})
    sleep(1)
    updatable.put([4])
    sleep(1)
    updatable.put(5,)  # will never be consumed 
    sleep(1)
    updatable.put(6)

if __name__ == '__main__':
    updatable = Updatable()
    p = multiprocessing.Process(target=consumer, args=(updatable,))
    p.start()
    producer()

0 个答案:

没有答案