Я перебираю строки в большом количестве загруженных текстовых файлов и сопоставляю регулярные выражения в каждой строке.Обычно матч занимает не более секунды.Однако иногда сопоставление занимает несколько минут, иногда сопоставление не заканчивается вообще, а код просто зависает (пару раз подождал час, потом сдался).Поэтому мне нужно ввести какое-то время ожидания и сказать коду соответствия регулярному выражению каким-то образом остановиться через 10 секунд или около того.Я могу жить с тем фактом, что я потеряю данные, которые должно было возвращать регулярное выражение.
Я попробовал следующее (что, конечно, уже представляет собой 2 разных решения на основе потоков, показанных в одном примере кода):
def timeout_handler():
print 'timeout_handler called'
if __name__ == '__main__':
timer_thread = Timer(8.0, timeout_handler)
parse_thread = Thread(target=parse_data_files, args=(my_args))
timer_thread.start()
parse_thread.start()
parse_thread.join(12.0)
print 'do we ever get here ?'
но я не получаю ни timeout_handler called
, ни do we ever get here ?
строки в выводе, код просто застрял в parse_data_files
.
Еще хуже, я не могудаже остановите программу с помощью CTRL-C
, вместо этого мне нужно найти номер процесса python и убить этот процесс.Некоторые исследования показали, что ребята из Python знают, что код regex C убегает: http://bugs.python.org/issue846388
Я добился некоторого успеха с помощью сигналов:
signal(SIGALRM, timeout_handler)
alarm(8)
data_sets = parse_data_files(config(), data_provider)
alarm(0)
это получаетсямне строка timeout_handler called
в выводе - и я все еще могу остановить свой скрипт, используя CTRL-C
.Если я сейчас изменю обработчик timeout_handler следующим образом:
class TimeoutException(Exception):
pass
def timeout_handler(signum, frame):
raise TimeoutException()
и заключу фактический вызов в re.match(...)
в предложении try
... except TimeoutException
, совпадение с регулярным выражением действительно прерывается.К сожалению, это работает только в моем простом однопоточном скрипте-песочнице, который я использую, чтобы попробовать что-то.В этом решении есть несколько недостатков:
- сигнал срабатывает только один раз, если имеется более одной проблемной строки, я застрял на второй
- таймераотсчет начинается сразу же, а не тогда, когда начинается фактический синтаксический анализ
- из-за GIL, я должен выполнить настройку всех сигналов в основном потоке, а сигналы принимаются только в основном потоке;это противоречит тому факту, что несколько файлов должны анализироваться одновременно в разных потоках - также возникает только одно глобальное исключение тайм-аута, и я не вижу, как узнать, в каком потоке мне нужно реагировать на него
- Я уже несколько раз читал, что потоки и сигналы не очень хорошо сочетаются
Я также подумал о том, чтобы сопоставить регулярное выражение в отдельном процессе, но прежде чем я углубился в это, я подумал:Лучше проверить здесь, сталкивался ли кто-нибудь с этой проблемой раньше и мог бы дать мне несколько советов о том, как ее решить.
Обновление
регулярное выражение выглядит так (ну, в любом случае, один из них,проблема возникает и с другими регулярными выражениями, это самое простое):
'^(\d{5}), .+?, (\d{8}), (\d{4}), .+?, .+?,' + 37 * ' (.*?),' + ' (.*?)$'
пример данных:
95756, "KURN ", 20110311, 2130, -34.00, 151.21, 260, 06.0, -9999.0, -9999.0, -9999.0, -9999.0, -9999.0, -9999, -9999, 07.0, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -
AsТем не менее, регулярное выражение обычно работает нормально - я могу проанализировать несколько сотен файлов с несколькими сотнями строк менее чем за минуту.Однако, когда файлы завершены, код кажется зависшим с файлами с неполными строками, такими как, например,
`95142, "YMGD ", 20110311, 1700, -12.06, 134.23, 310, 05.0, 25.8, 23.7, 1004.7, 20.6, 0.0, -9999, -9999, 07.0, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999
Я также получаю случаи, когда регулярное выражение возвращаетсразу и сообщает о несоответствии.
Обновление 2
Я только быстро прочитал катастрофическую статью , но, насколько я могу судить, этоне причина - я не вкладываю никаких операторов повторения.
Я на Mac OSX, поэтому я не могу использовать RegexBuddy для анализа моего регулярного выражения.Я попытался RegExhibit (который, очевидно, использует движок Perl RegEx для внутреннего использования) - и это тоже убегает.