背景
为了从逻辑控制器捕获数据,我使用screen作为终端模拟器,并通过KeySpan USA-19HS USB Serial Adapter连接我的MacBook。我创建了下面的bash脚本,以便可以键入talk2controller <filename>
,其中file name是数据文件的名称。
#!/bin/bash
if [ -z "$1" ]; then
echo Please provide the filename to save the logfile
exit
fi
LOGFILE=$1
echo "logfile $1" > screenrc # Set the logfile filename
echo "logfile flush 1" >> screenrc # Wait 1 sec before flushing buffer to filesystem
screen -L -c screenrc /dev/tty.KeySerial1 19200
我已经更改了日志文件的文件名,并从默认的10秒更改为1秒,以便在将日志文件缓冲区刷新到文件系统之前等待。我将这些命令保存到
screenrc
。然后我给屏幕打电话:-L
-日志记录已启用-c screenrc
-覆盖默认配置文件/dev/tty.KeySerial1 19200
-使用19200波特率与串行端口通话我记录的每个测试大约需要3-6分钟,包含速度、加速度和位置信息。我会知道根据加速度测试是有效的。目前,我正在等待测试结束后运行Pythonmatplotlib脚本来绘制速度、加速度和位置,以查看测试是否有效,然后再转到下一个测试。
为了节省时间,我宁愿在测试进行到一半时绘制数据,而数据仍在捕获中。
问题
在我看来,有两种方法可以在捕获更多数据时绘制数据:
选项1:使用screen记录数据,并让Python matplotlib脚本读取部分日志文件。
问题1:如果Python脚本读取日志文件,而screen仍在向其写入数据,会有什么问题?
选项2:从使用屏幕切换到使用pySerial。但是,在测试期间绘制数据的优先级比在测试期间简单地捕获数据的优先级低。我无法承受代码的绘图部分出现异常而导致数据记录失败。这就是screen的优点,它只会转储数据,而不会尝试做其他任何事情。
问题2:如果我切换到pySerial,我可以运行两个线程来减少代码的绘图部分不影响数据捕获代码的可能性吗?这能给我买点什么吗?
问题3:有没有一个我没想到的更好的选择?
最佳答案
选项1和选项2都可以,但是哦,天哪,以一切美好的名义,避免使用线程!您将以两个世界中最糟糕的结果结束:锁定问题,而绘图线程中的异常无论如何都会杀死整个程序(包括日志线程)。正如其他人提到的,使用两个独立的过程来实现这一点是很好的。screen
在这方面的工具选择有点奇怪,用python手工编写代码也是如此。我只是把talk2controller脚本重写为一个小脚本:
stty -F /dev/tty.KeySerial1 19200 raw
cat </dev/tty.KeySerial1 >logfile
(如果希望每次运行的脚本都附加到文件中,而不是从头重写,也可以使用
>>logfile
。)另一个问题是,只要有其他人在写文件,程序是否可以从文件中读取。这个问题的一个更具体的版本是:如果一行日志在您试图阅读时被写了一半呢?
答案是:你可以这么做,但你是对的,你不能保证一行字在你读的时候不会写一半。(如果您自己编写了
cat
或screen
的替换项,那么您实际上可以通过始终使用os.read()
而不是sys.stdout.write()
或print
写入文件来保证)然而,无论如何也不需要这种保证。你只需要在阅读文件时小心,就不会有问题。本质上,不完整的行只是不以换行符结尾的行。因此:
for line in open('logfile'):
if not line.endswith('\n'): break
...handle valid line...
由于
\n
字符是日志每一行最后写入的内容,因此您肯定知道,如果您读取了\n
字符,则它之前的所有内容都将正确写入。