How to set a time limit on a java function running a regex

后端 未结 10 846
难免孤独
难免孤独 2020-12-17 02:41

I am running a regex in a java function to parse a document and return true if it has found the string specified by the regex and return false if it hasn\'t. But the problem

相关标签:
10条回答
  • 2020-12-17 03:00

    I will assume for the moment that your regexp code is correct, and it really is some computational code that is CPU-bound for 6s.

    Given the above, I think you have only one option. To execute your code in a number of stages/iterations and check a variable for a request to halt. You can't do this using the normal Pattern/Matcher code.

    You could do this by splitting your input string beforehand in some fashion, and then feeding to your regexp bit by bit (your initial split would have to be independent of your regexp).

    You can't do this by:

    1. using Thread.stop() etc. This has been deprecated and doesn't work properly.
    2. Using Thread.interrupt(). This sets an interrupted flag on the thread which is only checked when the thread performs IO. If the thread is CPU-bound, then that flag will never be checked.

    Given the above, I would look again at why the regexp is taking 6s to match. Is the regexp correct ? Can you perform a regexp on smaller text segments ?

    0 讨论(0)
  • 2020-12-17 03:02

    I might be mistaken here, but I think all ways to terminate a thread have been deprecated for some time. The recommended way is to use a shared isRunning variable that your worker thread periodically checks and gracefully exits when it's been set.

    This will not work in your case, but it looks to me like you're treating the symptom - not the real problem. You should post the code of your regexp function, that takes 6 seconds to execute. If it's the regexp itself, the execution time may be a case of catastrophic backtracking.

    0 讨论(0)
  • 2020-12-17 03:03

    There are two ways to answer this question.

    On the one hand, there is no practical/effective way that is known to be safe of killing a thread that is executing Matcher.find(...) or Matcher.match(...). Calling Thread.stop() would work, but there are significant safety issues. The only way to address this would be to develop your own regex engine that regularly checked the interrupted flag. (This is not totally impractical. For example, if GPL wasn't an issue for you, you could start with the existing regex engine in OpenJDK.)

    On the other hand, the real root of your problem is (most likely) that you are using regexes the wrong way. Either you are trying to do something that is too complicated for a single regex, or your regex is suboptimal.

    EDIT: The typical cause of regexes taking too long is multiple quantifiers (?, , +) causing pathological backtracking. For example, if you try to match a string of N "A" characters followed by a "B" with the regex "^AAAAAA$", the complexity of the computation is (at least) O(N**5). Here's a more "real world" example:

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

    Now imagine what happens if you encounter a "web page" like this:

    <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>
    

    Notice that there is no closing </html> tag. This will run for a long time before failing. (I'm not exactly sure what the complexity is ... but you can estimate it experimentally it you feel like it.)

    In this case, a simple answer is to use simpler regexes to locate the 6 marker elements and then extract the stuff between then using substring().

    0 讨论(0)
  • 2020-12-17 03:03

    Start your thread via an ExecutorService and give it a timeout, like so:

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

    awaitTermination() will wait until the task is finished (as well as all other tasks under this ExecutorService), the thread is interrupted, or timeout occurs - which ever comes first.

    Sounds like this fits your needs.

    0 讨论(0)
  • 2020-12-17 03:03

    The Java Thread class is not equipped to deal with this sort of interruption, and as such is not suitable for your requirements.

    I would implement the functionality in a separate Process using the ProcessBuilder and use the Input and Output streams provided by the Process class for communication. Forceful interruption is provided by the destroy method of of the Process class.

    I believe this is the correct, safest, implementation for the requirements you have. Unfortunately, Java doesn't make it easy to launch another Java process in a platform independent way so you'll have to have the java executable to your path and create a separate main method to do this. This is harder than it should be.

    0 讨论(0)
  • 2020-12-17 03:17

    I agree to check the regular expressions before they are used. If you need a safety net, you might use something like this...

    http://gist.github.com/630969

    0 讨论(0)
提交回复
热议问题