Реализация простого опроса файла результатов
Для одного из моих модулей сбора данных диссертации я реализовал простой механизм опроса. Это необходимо, потому что я делаю каждый запрос на сбор данных (один из многих) в виде SQL-запроса, представленный через веб-форму, который имитируется кодом RCurl. Сервер обрабатывает каждый запрос и генерирует текстовый файл с результатами по определенному URL-адресу (RESULTS_URL
в коде ниже). Независимо от запроса, URL и имя файла совпадают (я не могу это изменить). Поскольку время обработки для разных запросов данных, разумеется, различно, и некоторые запросы могут занимать значительное количество времени, мой код R
должен "знать", когда результаты готовы (файл сгенерирован), чтобы он мог извлеките их. Следующее - мое решение для этой проблемы.
POLL_TIME <- 5 # polling timeout in seconds
В функции srdaRequestData()
перед выполнением запроса данных:
# check and save 'last modified' date and time of the results file
# before submitting data request, to compare with the same after one
# for simple polling of results file in srdaGetData() function
beforeDate <- url.exists(RESULTS_URL, .header=TRUE)["Last-Modified"]
beforeDate <<- strptime(beforeDate, "%a, %d %b %Y %X", tz="GMT")
<making data request is here>
В функции srdaGetData()
, вызываемой после srdaRequestData()
# simple polling of the results file
repeat {
if (DEBUG) message("Waiting for results ...", appendLF = FALSE)
afterDate <- url.exists(RESULTS_URL, .header=TRUE)["Last-Modified"]
afterDate <- strptime(afterDate, "%a, %d %b %Y %X", tz="GMT")
delta <- difftime(afterDate, beforeDate, units = "secs")
if (as.numeric(delta) != 0) { # file modified, results are ready
if (DEBUG) message(" Ready!")
break
}
else { # no results yet, wait the timeout and check again
if (DEBUG) message(".", appendLF = FALSE)
Sys.sleep(POLL_TIME)
}
}
<retrieving request results is here>
Основной поток/последовательность событий модуля является линейным, следующим образом:
Read/update configuration file
Authenticate with the system
Loop through data requests, specified in configuration file (via lapply()),
where for each request perform the following:
{
...
Make request: srdaRequestData()
...
Retrieve results: srdaGetData()
...
}
Проблема с приведенным выше кодом заключается в том, что она не работает , как ожидалось: при выполнении запроса данных код должен печатать "Ожидание результатов"...", а затем, периодически проверяя файл результатов для изменения (сгенерированный), печатайте точки выполнения до тех пор, пока результаты не будут готовы, когда он распечатает подтверждение. Однако фактическое поведение заключается в том, что код ждет много времени (я намеренно сделал один запрос долговременным), а не печатал что-либо, но затем, по-видимому, извлекает результаты и печатает как "Ожидание результатов".. "и "Готов" в то же время.
Мне кажется, что это какая-то проблема синхронизации, но я не могу понять, что именно. Или, может быть, это что-то еще, и я как-то пропустил это. Ваши советы и помощь будут очень благодарны!
Ответы
Ответ 1
В комментарии к вопросу, я считаю, что MrFlick
решил проблему: логика опроса кажется функциональной, но проблема в том, что сообщения о ходе не синхронизируются с текущими событиями в системе.
По умолчанию вывод консоли R буферизируется. Это по дизайну: ускорить работу и избежать отвлекающего мерцания, которое может быть связано с частыми сообщениями и т.д. Мы склонны забывать об этом факте, особенно после того, как мы использовали R в очень интерактивном режиме, запуская различные объявления ad-hoc на консоли (консольный буфер автоматически размывается перед возвратом приглашения >
).
Однако можно получить message()
и более общий вывод консоли в "реальном времени" путем явного промывания консоли после каждого критического оператора вывода с использованием функции flush.console()
или путем отключения буферизации на уровне R GUI (щелкните правой кнопкой мыши на консоли, см. Пункт Buffered output Ctrl W
. Это также доступно в меню Misc
)
Здесь показан пример использования явного использования flush.console. Обратите внимание на использование cat()
, а не message()
, поскольку первое не добавляет CR/LF к выходу автоматически. Последнее, однако, полезно, однако, поскольку его сообщения могут быть подавлены с помощью suppressMessages()
и тому подобного. Также, как показано в комментарии, вы можете нарисовать символ "\ b" (backspace), чтобы номер перезаписывался.
CountDown <- function() {
for (i in 9:1){
cat(i)
# alternatively to cat(i) use: message(i)
flush.console() # <<<<<<< immediate ouput to console.
Sys.sleep(1)
cat(" ") # also try cat("\b") instead ;-)
}
cat("... Blast-off\n")
}
Вывод следующий: в этом распечатке, конечно, не видно, что в течение всего 10 секунд каждое число было напечатано, прежде чем окончательный "Blast off"; удалите инструкцию flush.console(), и вывод будет выполнен сразу, через 10 секунд, то есть когда функция завершится (если консоль не буферизована на уровне графического интерфейса пользователя).
CountDown() 9 8 7 6 5 4 3 2 1... Взрыв