Чтение файла в Python при регистрации данных на экране - PullRequest
2 голосов
/ 14 сентября 2010

Фон

Для захвата данных с логического контроллера я использую screen в качестве эмулятора терминала и подключаю мой MacBook через USB-адаптер KeySpan USA-19HS * .Я создал следующий скрипт 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

Я изменил имя файла дляlogfile и изменил значение по умолчанию с 10 секунд до 1 секунды для ожидания перед сбросом буфера файла журнала в файловую систему.Я сохраняю эти команды в screenrc.Затем я вызываю экран с помощью:

  1. -L - ведение журнала включено
  2. -c screenrc - переопределение файла конфигурации по умолчанию
  3. /dev/tty.KeySerial1 19200 - разговор с серийнымпорт с использованием скорости передачи 19200

Каждый регистрируемый тест занимает около 3–6 минут и содержит информацию о скорости, ускорении и положении.Я буду знать, что тест был действительным на основе скорости ускорения.В настоящее время я жду до окончания теста, чтобы запустить скрипт Python matplotlib , чтобы отобразить скорость, ускорение и положение, чтобы проверить, был ли тест действительным, прежде чем переходить к следующему тесту.

Чтобы сэкономить время, я бы предпочел нанести данные примерно на полпути теста, пока они еще собираются.

Вопросы

На мой взгляд, есть два варианта построения графика.данные, в то время как еще больше данных захватывается:

  • Опция 1: Используйте экран для регистрации данных и заставить скрипт Python matplotlib прочитать частичный файл журнала.
    • Вопрос 1: Какие проблемы возникают, если скрипт Python читает файл журнала, в то время как экран все еще записывает в него данные?
  • Вариант 2: Переключение с использования экрана на использование pySerial .Однако построение данных во время теста является более низким приоритетом, чем простое получение данных во время теста.Я не могу допустить исключения в части кода для построения графика, которая может привести к сбою регистрации данных.Вот что хорошо в экране: он просто сбрасывает данные и больше ничего не пытается делать.
    • Вопрос 2: Если бы я переключился на pySerial, мог бы я запустить два потока, чтобы уменьшить вероятность того, что графическая часть кода не повлияет на код захвата данных?Это мне что-нибудь покупает?

Вопрос 3: Есть ли лучший вариант, о котором я даже не думал?

Ответы [ 3 ]

3 голосов
/ 17 сентября 2010

Оба варианта 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.)

Однако эта гарантия все равно не нужна. Вам нужно только быть осторожным при чтении файла, и у вас никогда не будет проблем. По сути, неполная строка - это всего лишь строка, которая не заканчивается символом \n новой строки. Таким образом:

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

Поскольку символ \n является последним, что пишется каждой строкой журнала, вы точно знаете, что если вы прочитали символ \n, все до того, как оно было написано правильно.

1 голос
/ 14 сентября 2010

Я бы сказал, вариант 2 - это путь. Вы имеете полный контроль над тем, что вы делаете с каждым байтом ввода, по мере его получения. У вас может быть очень простой скрипт Python, который просто записывает данные на диск по мере их чтения. Ваш код печати может выполняться в совершенно отдельном процессе, созданном fork() первым. Чтобы получить данные от одного к другому, вы можете (а) сделать так, чтобы первый процесс также записывал в socketpair() или другой механизм IPC; или (b) сконфигурировать объект выходного файла для буферизации строки - вызывая его явную синхронизацию после записи каждой полной строки - и отслеживать его на предмет нового контента во втором процессе.

Проблема с вариантом 1 заключается в том, что вы не можете контролировать поведение буферизации screen. Вы можете отслеживать его файл журнала на наличие нового контента, но ваш код регистрации должен быть подготовлен для обработки как неполных строк, так и больших кусков данных одновременно. В зависимости от точного поведения буферизации, вы можете даже не увидеть никаких данных, пока не завершится процесс screen!

1 голос
/ 14 сентября 2010

Я думаю, Вариант 1 вполне осуществим, потому что вы можете легко получить "хвост" Python для файла журнала в канале, доступном только для чтения, чтобы не причинить ему вреда, пока screen все еще пишет в него , При настройке файла вы можете выполнять указанное действие в любое время, когда в файле журнала обнаруживается новое событие журнала.

Если вам интересно, и вы хотели бы увидеть какой-нибудь рабочий код, мой личный проект использует эту функцию. Проект называется thrasher-logdrop , а кишки - logdrop.py . Основной поток:

  • Хвост файла с do_tail()
  • Следите за событиями журнала с tail_lines()
  • Выполнить действие над событиями с handle_line()
...