在屏幕中记录数据时用Python读取文件

时间:2010-09-14 14:13:35

标签: python matplotlib logging gnu-screen

背景

要从逻辑控制器捕获数据,我使用screen作为终端仿真器,并通过KeySpan USA-19HS USB Serial Adapter连接我的MacBook。我创建了以下bash脚本,以便我可以键入talk2controller <filename>,其中 filename 是数据文件的名称。

#!/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。然后我用以下方式调用屏幕:

  1. -L - 已启用日志记录
  2. -c screenrc - 覆盖默认配置文件
  3. /dev/tty.KeySerial1 19200 - 使用波特率19200
  4. 与串口通信

    我记录的每个测试大约需要3-6分钟,包含速度,加速度和位置信息。我知道测试基于加速率是有效的。目前,我等待测试后再运行Python matplotlib脚本来绘制速度,加速度和位置,以确定测试是否有效,然后再进行下一次测试。

    为了节省时间,我宁愿在测试中途绘制数据,同时仍在捕获数据。

    问题

    在我看来,有两种方法可以绘制数据,同时仍然可以捕获更多数据:

    • 选项1:使用屏幕记录数据并让Python matplotlib脚本读取部分日志文件。
      • 问题1:如果Python脚本读取日志文件,而屏幕仍在向其写入数据,那么会有什么问题?
    • 选项2:从使用屏幕切换到使用pySerial。但是,在测试期间绘制数据的优先级低于在测试期间简单捕获数据的优先级。我无法承担代码的绘图部分中的异常,导致数据记录失败。这就是屏​​幕的优点 - 它只是转储数据而不会尝试做任何其他事情。
      • 问题2:如果我要切换到pySerial,我可以运行两个线程来减少代码的绘图部分不会影响数据捕获代码的可能性吗?这给我买了什么吗?

    问题3:我有没有想过更好的选择?

3 个答案:

答案 0 :(得分:3)

选项1和2都可以使用,但是哦,男孩,以所有好事的名义,避免使用线程!你最终会遇到两个世界中最糟糕的事情:锁定问题,图形线程中的异常无论如何都会杀死整个程序(包括日志记录线程)。正如其他人提到的那样,使用两个单独的过程就可以了。对于这个目的,screen是一个奇怪的工具选择,就像在python中手动编写代码一样。我只是将talk2controller脚本重写为这个简单的脚本:

stty -F /dev/tty.KeySerial1 19200 raw
cat </dev/tty.KeySerial1 >logfile

(如果您希望每次运行脚本都附加到文件,而不是从头开始重写,也可以使用>>logfile。)

另一个问题是,只要其他人正在写文件,是否可以从文件中读取程序。这个问题的一个更具体的版本是:如果在您尝试阅读时,日志行是半写的,该怎么办?

答案是:你被允许这样做,但是你是对的,你不能保证在你阅读它时不会写一行。 (如果您为catscreen编写了自己的替代品,您实际上可以通过始终使用os.read()而非sys.stdout.write()print写入文件来实现此保证。 。)

但是,无论如何都不需要这种保证。您只需要在阅读文件时要小心,否则您将永远不会遇到问题。从本质上讲,不完整的行只是一个不以\n换行符结尾的行。因此:

for line in open('logfile'):
    if not line.endswith('\n'): break
    ...handle valid line...

由于\n字符是日志的每一行写的最后一个字符,因此您肯定知道如果您读取\n字符,那么它之前的所有内容都是正确写入的。

答案 1 :(得分:1)

我认为选项1 是完全可行的,因为您可以轻松地将Python“尾随”日志文件放在只读管道中,以便在screen仍然存在时不会对其造成任何伤害写给它。在拖尾文件时,只要在日志文件中检测到新的日志事件,就可以执行指定的操作。

如果您很好奇并希望看到一些正常工作的代码,我的个人项目会利用此功能。该项目名为thrasher-logdrop,胆量为logdrop.py。基本流程是:

  • 使用do_tail()
  • 定制文件
  • 使用tail_lines()
  • 关注日志事件
  • handle_line()
  • 的活动执行操作

答案 2 :(得分:1)

我说选项2是要走的路。当您收到输入时,您可以完全控制对输入的每个字节执行的操作。您可以拥有一个非常简单的Python脚本,它只是在读取数据时将数据写入磁盘。您的绘图代码可以在fork()第一个创建的完全独立的流程中运行。要从一个到另一个获取数据,您可以(a)让第一个进程也写入socketpair()或其他IPC机制;或者(b)将输出文件对象配置为行缓冲 - 使其在每写完整行后显式同步 - 并在第二个进程中监视它以获取新内容。

选项1的问题在于您无法控制screen的缓冲行为。您可以监视其日志文件以获取新内容,但您的日志记录代码需要准备好同时处理不完整的行和大块数据。根据确切的缓冲行为,在screen进程退出之前,您甚至可能根本看不到任何数据!