对我来说,一个相当常见的情况是定期更新一个值,比如说每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()