Я перебираю строки в большом количестве загруженных текстовых файлов и выполняю сопоставление с регулярным выражением в каждой строке. Обычно матч занимает меньше секунды. Однако иногда матч занимает несколько минут, иногда матч вообще не заканчивается и код просто зависает (пару раз подождал час, потом сдался). Поэтому мне нужно ввести какой-то тайм-аут и сообщить коду соответствия регулярного выражения, чтобы он остановился через 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, называемого
, ни , мы когда-нибудь доберемся здесь?
в выводе, код просто застрял в parse_data_files
.
Даже даже хуже того, я даже не могу остановить программу с помощью CTRL-C
, вместо этого мне нужно найти номер процесса python и убить этот процесс. Некоторые исследования показали, что ребята из Python знают, что код регулярного выражения C убегает: http://bugs.python.org/issue846388
Я действительно добился некоторого успеха, используя сигналы:
signal(SIGALRM, timeout_handler)
alarm(8)
data_sets = parse_data_files(config(), data_provider)
alarm(0)
это дает мне строку timeout_handler, называемую
, в выводе - и я все еще могу остановить свой скрипт, используя CTRL-C
. Если я теперь изменю timeout_handler следующим образом:
class TimeoutException(Exception):
pass
def timeout_handler(signum, frame):
raise TimeoutException()
и заключу фактический вызов re.match (...)
в try
... за исключением TimeoutException
, соответствие регулярному выражению действительно прерывается. К сожалению, это работает только в моем простом однопоточном сценарии песочницы, который я использую, чтобы попробовать разные вещи. В этом решении есть несколько ошибок:
. Я также рассматривал возможность сопоставления регулярных выражений в отдельном процессе, но прежде чем я перейду к этому, я подумал, что лучше проверить здесь, не сталкивался ли кто-нибудь эта проблема раньше и могла бы дать мне несколько советов, как ее решить.
регулярное выражение выглядит так (ну, в любом случае, одно из них, проблема возникает и с другими регулярными выражениями; это самый простой):
'^ (\ 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, -
Как сказано, regex обычно работает нормально - я могу проанализировать несколько сотен файлов с несколькими сотнями строк менее чем за минуту. Однако именно тогда файлы будут завершены - код, кажется, зависает с файлами с неполными строками, такими как, например,
`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
Я также получаю случаи, когда регулярное выражение, кажется, сразу возвращается и сообщает о несоответствии.
Я только быстро прочитал катастрофическую статью , но, насколько я могу судить, причина не в этом - я не вкладываю никаких операторов повторения.
У меня Mac OSX, поэтому я не могу использовать RegexBuddy для анализа моего регулярного выражения. Я попробовал RegExhibit (который, по-видимому, использует внутри Perl RegEx движок) - и это тоже убегает.