python - 记录数据并同时检查条件的最有效方法?

标签 python multithreading raspberry-pi

我正在尝试为 rapspbery pi 编写一个 python 代码来控制一个非常特殊的设备,它是一个杠杆(末端有一个旋转编码器)和一些 LED。 本质上,一个人将控制杆拉到特定范围的位置,如果操作正确,LED 将亮起,指示您处于目标位置。 杠杆可能会在编码器计数的特定范围内移动,您仍然会成功完成试验。 我的问题是,记录杠杆位置数据同时能够检查杠杆是否处于正确位置范围内的最佳方法是什么?

我已经为这个程序的一个简单版本编写了软件,它只使用一个开关而不是旋转编码器作为杠杆。编码器的优点是我可以非常精确地测量杠杆位置,从而获得更多数据!我可以想办法记录数据,唯一的问题是它会很慢。我正在考虑使用一个嵌套的 while 循环,其中循环将检查并记录杠杆的位置,但恐怕这个选项的采样率可能会非常低。

我也在考虑使用线程来实现这个目标,但是我不知道如何使用线程来做到这一点,因为我以前从未使用过它们。

我已经拥有与编码器本身接口(interface)的软件和硬件,我能够获得非常好的杠杆位置数据,但是我希望能够同时记录尽可能多的这些数据点时间仍然能够检查杠杆是否在正确的位置范围内。

如果您能向我展示执行此操作的简单代码并且我应该能够在我的代码中实现它,我将不胜感激。

这是我目前正在考虑如何编写代码的一个简单示例:

minCorrectPos = 100
maxCorrectPos = 200
timeToHoldLever = 5.0 #Seconds

while True:
    currentPos = encoder.readEncoderPos() #Function returns int
    writeToFile(str(currentPos)) #Records the data pos of the lever. I want this to happen as often as physically possible so as to lose the least amount of data.
    if currentPos < minCorrectPos or currentPos > maxCorrectPos:
        print 'Lever is out of range, wrong trial'
        writeData(timestamp)
    if time.time()-t_trialBegin > timeToHoldLever:
        print 'Lever has been held for enough time within correct range of positions. Rewarding person.'
        break
    #... 
    #Potentially checking for more things, like status of subject, whether he or she is still touching the lever, etc.

我不喜欢上面代码的原因是我担心我会丢失数据,因为树莓派可能无法足够快地轮询控制杆的位置,因为正在进行的 while 循环(缓慢的采样)速度)。这就是为什么我认为线程可能是解决这个问题的正确方法,因为我将有一个单独的线程运行,专门用于记录杠杆位置,给出拉动杠杆的对象的名字。遗憾的是,我在编写此类代码时需要帮助。

最佳答案

我建议使用 multiprocessing模块而不是线程,因为全局解释器锁 (GIL) 阻止 Python 并发执行线程,即使是在多核的情况下。 multiprocessing 模块避免了这个限制。

这是一个小示例,展示了如何通过使用 multiprocessing.Pipe 发送 currentPos,让子进程专用于将 currentPos 写入文件 父子进程之间。

import multiprocessing as mp

def writeToFile(conn):
    with open(filename, "a") as f: # Just leave the file open for performance reasons.
        while True:
            currentPos = conn.recv()        
            f.write("{}\n".format(currentPos))

if __name__ == "__main__":
    parent_conn, child_conn = mp.Pipe()
    p = mp.Process(target=writeToFile, args=(child_conn,))
    p.start()
    while True:
        currentPos = encoder.readEncoderPos()
        parent_conn.send(currentPos)
        if currentPos < minCorrectPos or currentPos > maxCorrectPos:
            print 'Lever is out of range, wrong trial'
            writeData(timestamp)
        if time.time()-t_trialBegin > timeToHoldLever:
            print 'Lever has been held for enough time within correct range of positions. Rewarding pe'
            break

请注意,尽管我之前曾说过 Python 不能很好地处理线程,但与此特定示例中的 multiprocessing 相比,它们的性能可能相当出色。这是因为子进程主要是做I/O,这样就可以释放GIL。您可以使用 threading 模块尝试类似的实现并比较性能。

此外,您可能希望 writeToFile 仅在每 N 个 currentPos 值被接收后实际执行 f.write。文件 I/O 很慢,因此进行更少、更大的写入可能对您来说性能更好。

关于python - 记录数据并同时检查条件的最有效方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23965936/

相关文章:

python - Python无法在Raspberry Pi上编译

python - 特拉维斯 CI : Switch to python 3 temporarily

python - 为什么元类上的 .mro() 具有不同的签名? `descriptor ' 对象的 'type' mro' 需要一个参数`

python - 在 Python3 ubuntu 上安装 tkinter

java - 方法的线程安全

python - (Python)如何让用户打开一个文本文件,然后更改一个整数/数字

Asp.Net Core 2.0 Linux Arm - SQLIte 问题

python - 错误号 10061 : No connection could be made because the target machine actively refused it ( client - server )

python - 线程在 flask 中不起作用

java - 如何使用 synchronization(){} block 在 android 中保护方法免受并行访问