Как прекратить 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.

Если это звучит загадочно, попросите детали.

Если бы я был вами, я бы создал свой собственный класс, который я бы поместил между моим приложением и библиотекой, которую вы используете для сопоставления, и реализовал бы такие методы, как "прерывание", которые вам нужны, чтобы уничтожить поток, и таким образом управлять сопоставлением.

Другие вопросы по тегам