Как прекратить Matcher.find(), когда он работает слишком долго?
Хотите знать о методах завершения длительных совпадений регулярных выражений (метод java matcher.find()). Может быть, создание подкласса Matcher и добавление логики для завершения после x числа итераций?
По сути, я генерирую регулярные выражения с использованием генетического алгоритма, поэтому я не контролирую их. Затем я проверяю каждый из них на некоторый текст, чтобы увидеть, соответствуют ли они определенной целевой области текста.
Так как я как бы случайно генерирую эти регулярные выражения, я получаю некоторые сумасшедшие вещи, которые тратят кучу процессоров, и некоторым вызовам find () требуется некоторое время для завершения. Я бы предпочел просто убить их через некоторое время, но не уверен, что это лучший способ сделать это.
Так что если у кого-то есть идеи, пожалуйста, дайте мне знать.
6 ответов
Здесь есть решение, которое решит вашу проблему. (Этот вопрос - та же самая, что и ваша.)
По сути, это CharSequence, которая может замечать прерывания потока.
Код из этого ответа:
/**
* CharSequence that noticed thread interrupts -- as might be necessary
* to recover from a loose regex on unexpected challenging input.
*
* @author gojomo
*/
public class InterruptibleCharSequence implements CharSequence {
CharSequence inner;
// public long counter = 0;
public InterruptibleCharSequence(CharSequence inner) {
super();
this.inner = inner;
}
public char charAt(int index) {
if (Thread.interrupted()) { // clears flag if set
throw new RuntimeException(new InterruptedException());
}
// counter++;
return inner.charAt(index);
}
public int length() {
return inner.length();
}
public CharSequence subSequence(int start, int end) {
return new InterruptibleCharSequence(inner.subSequence(start, end));
}
@Override
public String toString() {
return inner.toString();
}
}
Оберните свою строку этим, и вы можете прервать поток.
Просто покажи другое решение.
Вы можете использовать алгоритм NFA, который не чувствителен к вводу и в сотни раз быстрее, чем стандартная библиотека Java.
Я думаю, что чувствительность к вводу является первоначальной причиной, которая вызывает вашу проблему.
Вы можете ознакомиться с введением здесь: сопоставление регулярных выражений может быть простым и быстрым (но медленным в Java, Perl, PHP, Python, Ruby, ...)
Я также ответил на аналогичный вопрос более подробно здесь: отменить длительное совпадение с регулярным выражением?
Наихудший сценарий, в котором люди могут кричать на меня:
Вы можете запустить сопоставление регулярных выражений в другом потоке, и если он выполняется слишком долго, вы можете thread.stop()
Это.
Одним из возможных решений, которое имеет приятную особенность в том, что он не блокирует основной поток, было бы создание "соответствия" в отдельном потоке. Вы можете создать индивидуальный Callable
который возвращается null
после того, как продолжительность / порог истек или результат "соответствия", если он успешен.
Вам нужно использовать другой поток и остановить его, когда у него заканчивается время.
Есть два способа остановки: Thread#stop() и Thread#interrupt().
Использование Thread.stop() довольно опасно, и Matcher не отвечает на Thread.interrupt (ответ на прерывание является обязательным поведением).
НО есть действительно умное решение, некоторые детали здесь. Используйте предоставленный InterruptibleCharSequence (он оборачивает вашу строку и работает почти как один, НО добавляет поддержку Thread#interrupt()), затем создайте свой собственный Callable, возвращающий все, что возвращает matcher. Каждый выполняемый модуль теперь может быть выполнен с использованием комбо FutureTask / ThreadPool, и вы можете получить результат с любым временем ожидания:
Boolean result = myMatchingTask().get(2, TimeUnit.SECONDS)
Если вы находитесь в среде Java EE, вы можете пропустить сложную часть, просто используйте вызовы InterruptipleCharSequence и @Asynchronous.
Если это звучит загадочно, попросите детали.
Если бы я был вами, я бы создал свой собственный класс, который я бы поместил между моим приложением и библиотекой, которую вы используете для сопоставления, и реализовал бы такие методы, как "прерывание", которые вам нужны, чтобы уничтожить поток, и таким образом управлять сопоставлением.