Multithreaded Java regex
I have 1 producer, M consumer template. The producer reads the raw document from disk and puts it in the LinkedBlockingQueue. Then each consumer thread takes the raw document and parses the document using the class
ParsedDoc article = parseDoc(rawDocument);
The parseDoc class is a collection of about 20 methods with the following pattern:
public String clearContent(String document) {
Pattern regex = Pattern.compile(pattern);
Matcher matcher = regex.matcher(document);
matcher.find();
....
}
public String removeHTML(String document) {
Pattern regex = Pattern.compile(pattern);
Matcher matcher = regex.matcher(document);
matcher.replaceAll("");
....
}
The problem I'm running into is that the code is running fast enough on my local (2 core) machine. But when I run the same code on an 8-core machine, the user's performance degrades almost to a halt. I tried to optimize the jvm options to no avail. Removing the regex processing step resulted in the expected performance increase of x4 on core 8. So the problem is with regexes. I understand that the pattern is thread safe and the pairing can be reset (). But the problem is how to reverse engineer the regex bank (in the parseDoc class) to be thread safe for M consumers.
Any help would be much appreciated
thank
source to share
The manufacturer's consumer sample does not scale well. The more producers or consumers you have, the higher your productivity. The reason is that the shared queue becomes a bottleneck for the entire system. Hope you can see how.
The best approach is not to have a common queue; each consumer hqve has its own queue. When a request comes in, it goes to the load balancer. The load balancer will place the request into the smallest consumer queue. The balancer becomes a bottleneck, but it does not perform many operations. Just picks the correct queue to send the incoming request - so it needs to be scrolled quickly.
Here's a change to answer your questions: Problem (in more detail) : The more cores you have, the slower it gets. What for? Common memory.
@Peyman uses ConcurrentLinkedQueue (which is a non-blocking wait queue where one queue and one deluxe can continue at the same time). Even try it on your original design and compare both designs. I expect your revised design to perform better because you can only have one session and one dequeue at a time, as opposed to one enqueue and n dequeue as in your original design (but these are just my assumptions).
A great article on a scalable consumer manufacturer using balancers
Read this page (or you can just look at "go from a normal work queue approach to a per thread queue approach")
Here is a list from http://www.javaperformancetuning.com/news/newtips128.shtml . I think the last 3 points are more applicable to you:
- Most server applications use a shared work queue and thread pool; the general queue of employees contains short tasks that come from remote sources; the thread pool retrieves tasks from the queue and processes the tasks; threads are blocked in the queue if there is no task to process.
- The feeder queue, shared between threads, is a bottleneck (from contention) when the number of tasks is large and the task time is very short. The bottleneck gets worse the more cores are used.
- Solutions available to overcome contention for shared queue access include: Using no-data locks; Using parallel data structures with multiple locks; Maintaining multiple queues to isolate contention.
- The queue-per-thread approach avoids contention on the queue access, but is not optimal when the queue is down while other queues have raw data in the queue. To improve this, idle threads should be able to steal work from other queues. To minimize contention, the "steal" should be done from the tail of another queue (where normal de-synchronization from the thread's own queue is done from the head of the queue).
source to share
Regular expression compilation is slow. You should only do this once for a given template. If the variable pattern
you referenced is indeed different for each call, the instances pattern
could probably be members of the class static
. A is pattern
clearly safe for multiple threads to use concurrently. (All mutable state is held Matcher
.)
Since it is Matcher
limited to a single thread stack, you don't need to worry about threading issues. Don't try to reuse Matcher
. It can be done, but I would be surprised if recycling them saves a lot of time compared to compiling regular expressions.
source to share