Как установить ограничение по времени на функции Java выполнение regex

Я выполняю regex в функции Java, чтобы проанализировать документ и возвратить true, если он нашел строку указанной regex и возвращает false, если он не имеет. Но проблема состоит в том, что, когда документ не содержит строку, указанную regex, требуется очень долгое время для возвращения false, и я хочу завершить ту функцию, если требуется больше чем 6 секунд для выполнения.

Как я могу установить ограничение по времени 6 секунд на той функции, чтобы насильственно завершить это, если требуется больше чем 6 секунд.

Я называю метод "методом 1" класса 2 от класса 1. "Метод 1" вызов "метод 2" того же класса т.е. "класса 2". Метод 2 выполнения regex кодирует по документу. Если это находит строку указанной regex, то это возвращает результат методу 1, которые в свою очередь возвращают результат методу в "классе 1" который названный "методом 1" класса 2. Теперь проблема состоит в том, что время выполнения и method1 и method2 класса 2 должно составить не больше чем 6 секунд.

Так, я сделал новый класс RegexpThread в том же файле, в котором мой class2 был. Затем я перемещаю method2 class2 в класс RegexpThread. Затем каждый раз, когда метод 1 называют, он инстанцирует класса RegexpThread следующим образом:

RegexpThread rt = new RegexpThread() {
    public void run() {
        method 2(m, urlCopy, document);
    }    
};

rt.start();

try {
    rt.join(6 * 1000);
} catch (InterruptedException e) {
    return "y";
}

if(rt.getResultXml().equals("")) {
    return "g";
}

resultXml.append(rt.getResultXml());

return resultXml.toString();

Показанный код находится в методе 1 из class2. Метод 2 в классе RegexpThread выполняет некоторый поиск regex по документу. Существует частное поле, названное "resultXml" в классе RegexpThread. Если метод 2 нашел строку указанной regex затем, это присваивает результат частному полю "resultXml". Если не затем "resultXml" содержит свое значение по умолчанию т.е. пустую строку.

Так, в вышеупомянутом, "если блок", это проверяет "resultXml" поле по пустой строке. Если это - пустая строка затем, это означает, что regex не нашел свою строку в документе. Но если это не пустая строка затем, это означает, что regex нашел строку в документе и присвоил результат "resultXml" полю.

таким образом посмотрите на это и скажите мне, что сделать...

5
задан Fábio Nascimento 27 June 2019 в 16:14
поделиться

7 ответов

То, что вы сделали, мне нравится, вот как я измените его:

final AtomicReference<String> resultXml = new AtomicReference<String>();

RegexpThread rt = new RegexpThread() {
  public void run() {
    method2(m, urlCopy, document, resultXml);
  }

};

rt.start();

try {
    rt.join(6 * 1000);
} catch (InterruptedException e) {
    return "y";
}

if(resultXml.get() == null) {
    rt.interupt();
    return "g";
}

resultXml.append(resultXml.get());

return resultXml.toString();
-2
ответ дан 13 December 2019 в 22:12
поделиться

Я могу ошибаться здесь, но я думаю, что все способы завершить поток уже давно устарели . Рекомендуемый способ - использовать общую переменную isRunning , которую ваш рабочий поток периодически проверяет и корректно завершает, когда она установлена.

Это не сработает в вашем случае, но мне кажется, что вы лечение симптома - не настоящая проблема. Вы должны опубликовать код своей функции регулярного выражения, выполнение которой занимает 6 секунд. Если это само регулярное выражение,

9
ответ дан 13 December 2019 в 22:12
поделиться

Есть два способа ответить на этот вопрос.

С одной стороны, не существует известного практического / эффективного способа, который, как известно, был бы безопасным для остановки выполняемого потока Matcher.find (...) или Matcher.match (...) . Вызов Thread.stop () будет работать, но есть серьезные проблемы с безопасностью. Единственный способ решить эту проблему - разработать собственный механизм регулярных выражений, который регулярно проверял бы флаг прерванный . (Это не совсем непрактично. Например, если GPL не проблема для вас, вы можете начать с существующего механизма регулярных выражений в OpenJDK.)

С другой стороны, настоящий корень вашей проблемы (скорее всего, ), что вы неправильно используете регулярные выражения. Либо вы пытаетесь сделать что-то слишком сложное для одного регулярного выражения, или ваше регулярное выражение неоптимально.

РЕДАКТИРОВАТЬ : Типичная причина того, что регулярные выражения занимают слишком много времени, - это множественные кванторы (?, , +), вызывающие патологический возврат. Например, если вы попытаетесь сопоставить строку из N символов «A», за которой следует «B», с регулярным выражением «^ A A A A A A $» , сложность вычисления (не менее) O (N ** 5). Вот более «реальный» пример:

"(.*)<html>(.*)<head>(.*)</head>(.*)<body>(.*)</body>(.*)</html>(.*)"

А теперь представьте, что произойдет, если вы встретите такую ​​«веб-страницу»:

<html><html><html><html><html><html><html><html><html><html>
<head><head><head><head><head><head><head><head><head><head>
</head></head></head></head></head></head></head></head></head></head>
<body><body><body><body><body><body><body><body><body><body><body>
</body></body></body></body></body></body></body></body></body></body>

Обратите внимание на отсутствие закрывающего тега . Это будет работать долго, прежде чем выйдет из строя. (Я не совсем уверен, в чем состоит сложность ... но вы можете оценить это экспериментально, если захотите.)

В этом случае,

2
ответ дан 13 December 2019 в 22:12
поделиться

Запустите свой поток через ExecutorService и дайте ему тайм-аут, например:

ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE);
pool.execute(rt);
pool.awaitTermination(timeout, timeUnit);

awaitTermination () будет ждать, пока задача не будет завершена (также как и все другие задачи в рамках этой ExecutorService ), поток прерывается или происходит тайм-аут - что наступит раньше.

Похоже, это соответствует вашим потребностям.

0
ответ дан 13 December 2019 в 22:12
поделиться

Вы не показываете функцию, которая фактически выполняет регулярное выражение, поэтому я предполагаю, что она считывает строки из файла и выполняет регулярное выражение для каждой строки.

Если это В этом случае лучшим решением будет передать этой функции значение тайм-аута. После каждых N строк (какими бы N могло быть) он проверяет значение тайм-аута.

Настоящая проблема, с которой вы столкнетесь, связана с блокировкой ввода-вывода - например, чтение из сети. В этом случае вы ничего не сможете сделать с Java, поскольку блокировка фактически происходит в ядре ОС.

0
ответ дан 13 December 2019 в 22:12
поделиться

Класс Java Thread не приспособлен для обработки такого рода прерываний и поэтому не подходит для ваших требований.

Я бы реализовал функциональность в отдельный процесс с использованием ProcessBuilder и использование потоков ввода и вывода, предоставленных классом Process для связи. Принудительное прерывание обеспечивается методом destroy класса Process .

Я считаю, что это правильная и самая безопасная реализация для ваших требований. К сожалению, Java не позволяет легко запускать другой процесс Java независимо от платформы, поэтому вам придется иметь исполняемый файл java на своем пути и создать для этого отдельный метод main . Это сложнее, чем должно быть.

0
ответ дан 13 December 2019 в 22:12
поделиться

На данный момент я предполагаю, что ваш код регулярного выражения правильный, и на самом деле это некоторый вычислительный код, привязанный к ЦП на 6 секунд.

Учитывая вышесказанное, я думаю, что у вас есть только один вариант. Выполнить ваш код в несколько этапов / итераций и проверить переменную на предмет остановки запроса. Вы не можете сделать это с помощью обычного кода Pattern / Matcher .

Вы можете сделать это, предварительно разделив входную строку каким-либо образом, а затем побитно передавая ее в ваше регулярное выражение (ваше начальное разделение должно быть независимым от вашего регулярного выражения).

Вы не можете делают это:

  1. с помощью Thread.stop () и т. Д. Это устарело и работает неправильно.
  2. Использование Thread.interrupt () . Это устанавливает флаг прерывания в потоке, который проверяется только тогда, когда поток выполняет ввод-вывод. Если поток привязан к процессору, то этот флаг никогда не будет проверяться.

Учитывая вышесказанное, я хотел бы еще раз посмотреть, почему регулярное выражение требует 6 секунд для сопоставления. Регулярное выражение правильное? Можете ли вы выполнить регулярное выражение для небольших текстовых сегментов?

2
ответ дан 13 December 2019 в 22:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: