我正在尝试编写一个基本方向的显示。我有一个以高刷新率运行的界面,以及一个每秒仅更新几次的硬件设备。
每次显示器更新时,我需要能够从硬件获取最新的报告值到显示器。
我目前的方法是尝试多处理。我有一个进程通过共享状态管道获取值并使用这些值更新对象,并且我有一个进程从对象中获取值并更新显示。
不幸的是,它似乎在某个地方被阻塞,并且显示被锁定到硬件更新速度。
class AccMag():
# Init manually to ensure access to and for internal functions
def init(self):
# This defines the hardware access
self.i2c = busio.I2C(board.SCL, board.SDA)
self.mag = adafruit_lis2mdl.LIS2MDL(self.i2c)
self.accel = adafruit_lsm303_accel.LSM303_Accel(self.i2c)
# Output values (mag#) and pipes to the other process
self.magx = 0
self.pipex = multiprocessing.Value('d', 0.0)
self.magy = 0
self.pipey = multiprocessing.Value('d', 0.0)
self.magz = 0
self.pipez = multiprocessing.Value('d', 0.0)
# The process, named thread. Yes, my cat is named Rex.
self.thread = multiprocessing.Process(target=self.threadmagdate, args=(self.pipex, self.pipey, self.pipez))
self.thread.start()
# A counter I use to see how often the process has run.
# Comparing this counter to a similar one in the display is how I know it's blocking.
self.tc = 0
# The function that starts the process to update the values
def magdate(self):
# Check the current process is done
self.thread.join(timeout=0)
if self.thread.is_alive() == False:
# Pull out previous values
self.magx = self.pipex.value
self.magy = self.pipey.value
self.magz = self.pipez.value
self.tc += 1
# Start a new process
self.thread = multiprocessing.Process(target=self.threadmagdate, args=(self.pipex, self.pipey, self.pipez))
self.thread.start()
# Get the data from the hardware into the pipe
def threadmagdate(self, magx, magy, magz,):
magx.value = int(self.mag.magnetic[1])
magy.value = int(self.mag.magnetic[0])
magz.value = int(self.mag.magnetic[2])
然后显示器可以调用 magdate() 并从 mag# 值中获取值。
我遗漏了一些明显的东西,我可以闻到它的味道,但我不知道为什么它会锁定。
self.thread.join(timeout=0)
似乎是毫无意义的代码行,因为 join()
通常用于等待进程完成一段时间,但在这种情况下,它实际上根本不等待。
根据您的代码,我没有看到任何可能阻塞的内容,但是在某些平台上,启动新进程可能需要一段时间(有时超过1秒)取决于进程启动方法。
鉴于
magdate()
每次被调用时都可能启动一个新进程,我怀疑这就是“阻塞”发生的地方。
因此,我建议不要每次在
magdate()
中启动一个新进程,而是使用 Queue
对象。
from multiprocessing import Queue, Process, Event
class AccMag():
# Init manually to ensure access to and for internal functions
def init(self):
# This defines the hardware access
self.i2c = busio.I2C(board.SCL, board.SDA)
self.mag = adafruit_lis2mdl.LIS2MDL(self.i2c)
self.accel = adafruit_lsm303_accel.LSM303_Accel(self.i2c)
# Set up queue and a termination event
self.queue = Queue()
self.terminate_event = Event()
# The process, named thread. Yes, my cat is named Rex.
self.thread = Process(target=self.threadmagdate, args=(self.queue, self.terminate_event))
self.thread.start()
# A counter I use to see how often the process has run.
# Comparing this counter to a similar one in the display is how I know it's blocking.
self.tc = 0
def stop(self):
self.terminate_event.set() ## trigger termination event
self.thread.join() ## wait for process to terminate
# The function that starts the process to update the values
def magdate(self):
# Check if new value is available
if not self.queue.empty():
x, y, z = self.queue.get()
# Pull out new values
self.magx = int(x)
self.magy = int(y)
self.magz = int(z)
self.tc += 1
# Get the data from the hardware into the pipe
def threadmagdate(self, queue, terminate_event):
while not terminate_event.is_set(): ## check if it's time to stop reading values
queue.put(self.mag.magnetic) ## insert new reading into queue