Python解释器中的后台线程在time.sleep()上挂起



我们已经构建了一个自定义的python解释器,并试图创建一个函数来启动一个后台线程,该线程定期调用一个函数以获取传感器读数,然后将读数存储在一个循环缓冲区中(使用最大长度的deque实现)。

下面显示了我们实现的精简版本。我们面临的问题是,当我们从解释器调用monitor_sensor()来启动后台线程时,后台线程中的代码似乎只执行了一次(这是我们通过查看sensor_values的内容来确定的)。此外,当我们尝试退出解释器(使用exit())时,解释器会挂起并且永远不会退出。

import code
import collections
import threading
def get_sensor_reading():
    return 5.0
sensor_values = {}
def monitor_sensor():
    sensor_values['sensor_1'] = collections.deque(maxlen=1000)
    background_thread = threading.Thread(target=run_monitor_sensor, args=[sensor_values, get_sensor_reading])
    background_thread.start()
def run_monitor_sensor(sensor_values, read_sensor_cmd):
    while True:
        reading = read_sensor_cmd()
        sensor_values['sensor_1'].append(reading)
        import time
        time.sleep(1)
imported_objects = {'monitor_sensor': monitor_sensor,
                    'sensor_values': sensor_values}
code.interact(local=imported_objects)

下面显示了解释器会话的转储,我们在其中尝试运行后台线程并查看存储的数据——请注意,在尝试读取sensor_values中的值之间,我们等待的时间远远超过1秒的睡眠时间。

218> python manage.py example
Python 2.7.3 (default, Aug  1 2012, 05:16:07) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> monitor_sensor()
>>> sensor_values
{'sensor_1': deque([5.0], maxlen=1000)}
>>> sensor_values
{'sensor_1': deque([5.0], maxlen=1000)}

问题似乎与对time.sleep(1)的调用有关——如果我们删除它,那么缓冲区将很快充满值。有人能告诉我们为什么会出现这个问题,以及我们如何解决它吗?

更新

我们通过将import time从循环内部移动到模块级来解决这个问题。到目前为止,还不知道为什么这样可以解决问题,但如果有人能回答这个问题,那么就会接受这个答案。

您在没有锁的两个线程之间共享一个可变值。

实际上,不能保证在Python中是一个问题,这可能不是你的问题……但这肯定是错误的,它可能会导致这样的问题。

要修复它,请执行以下操作:

sensor_values = {}
sensor_lock = threading.Lock()
def monitor_sensor():
    sensor_values['sensor_1'] = collections.deque(maxlen=1000)
    background_thread = threading.Thread(target=run_monitor_sensor, args=[sensor_values, get_sensor_reading, sensor_lock])
    background_thread.start()
def run_monitor_sensor(sensor_values, read_sensor_cmd, sensor_lock):
    while True:
        reading = read_sensor_cmd()
        with sensor_lock:
            sensor_values['sensor_1'].append(reading)
        import time
        time.sleep(1)
def get_sensor_values():
    with sensor_lock:
        return sensor_values

最新更新