Python线程安全访问没有阻塞或不受控制的队列增长?

时间:2014-11-11 02:12:15

标签: python multithreading

我有一个硬件传感器。我需要不断读取传感器并对之前3秒的读数进行一些数学计算。 (我读的越快,我的样本越多,我的结果就越好,所以我想不断调用我的函数。)我需要在请求时向用户(通过Web调用)提供当前结果。结果可能会在亚秒级基础上发生显着变化。用户可以尽可能快地或非常不频繁地请求更新。

我目前有以下代码,可以使用。

from threading import Thread
from MySensorReadAndMath import MySensorReadAndMath

class ManageSensor(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.result={}
        self.mySensorReadAndMath = MySensorReadAndMath()
    def updateResult(self):
        result = {}
        result['value1'] = self.mySensorReadAndMath.value1
        result['value2'] = self.mySensorReadAndMath.value2
        return result
    def getResult(self):
        return self.result
    def run(self):
        while True:
            self.mySensorReadAndMath.update()
            self.result = self.updateResult()

在另一段代码中,我创建了类,使用Flask创建对 ManageSensor.getResult()的Web调用以返回结果,并启动该线程。

这是线程安全的吗? (我可以获取当前的 value1 和之前的 value2 ,还是损坏的 self.result ?)如果它不是线程安全的,那么会怎样?我没有阻止它使它成为线程安全的吗?

我考虑的具体事项:

  1. 首先将值复制到 updateResults()中的本地结果中(直接将所有内容直接放入 self.result <中,我能获得任何好处吗? / em> in updateResult()
  2. 如果我在更新 self.result 时放置锁定,那么我的 run()循环或我的 getResult()可能阻止了我#39; t want。
  3. 如果我将结果推送到 run()中的队列并在 getResult()中弹出,我将遇到队列大小问题,因为我永远不会打电话 getResult() self.mySensorReadAndMath.update()一样快。
  4. 我是否过度思考这个? :)

2 个答案:

答案 0 :(得分:1)

通常我会尝试使用内置的Queue类,但这种情况可能太复杂了。

如果我理解正确,无论用户提出多少请求,您都需要存储三秒钟的数据。您可以通过利用Python始终通过引用访问对象的事实来解决此问题。分配引用是Python中的原子操作,因此您可以安全地使用单例来存储最新结果。有两个条件:

  1. 结果成员发布后必须没有作业分配
  2. 结果的用户必须在请求期间只检索一次结果:如果第二次检索结果,结果可能会更改。
  3. 因此,使用单例来强制执行此行为:

    class Buffer:
        ''' A simple buffer that stores exactly one value '''
        latest = None
        @staticmethod
        def onNewReading(*args, **kwds): # or any parameters one fancies
            # Pack the results in a single object and store it
            Result.latest = (args, kwds)
        @staticmethod
        def onUserRequest():
            return Result.latest
    

    写一个值如下:

    def process():
        # Do the measurement
        # Do the calculation
        Buffer.onNewReading(data1, data2, etc)
    

    使用值:

    def handleRequest():
        results = Buffer.onUserRequest()
        # Format a response, using the results
        if not results:
            return 'No data available'  # or any other useful error message
        return response(results[0][0], results[0][1])
    

答案 1 :(得分:0)

这不是线程安全的。

客户端线程可以在updateResult运行时调用getResult,因此结果可能为空,半满或包含旧值。

制作另一个对象并在之后将其分配给结果将限制半填充数据的可能性,因此这是一个加号。

队列解决方案还需要某种锁定