我有一个1生产者,M消费者线程模式。制作人从光盘中读取原始文档并将其放入LinkedBlockingQueue中。然后,每个使用者线程获取一个原始文档,并使用一个类解析该文档
ParsedDoc article = parseDoc(rawDocument);parseDoc类是一组大约由20个方法组成的方法,其模式如下:
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("");
....
}我面临的问题是代码在我的本地(2核)机器上运行得相当快。但是,当我在一台8核机器上运行相同的代码时,消费者的性能下降到几乎完全停顿。我尝试过优化jvm选项,但无济于事。删除正则表达式处理步骤可以在8核上获得预期的x4性能提升。所以问题出在正则表达式上。我意识到Pattern是线程安全的,而matcher可能需要被重置()。但问题是如何重新设计正则表达式库(在parseDoc类中),使其在M个使用者之间是线程安全的。
任何帮助都将不胜感激
谢谢
发布于 2012-03-18 14:32:17
生产者-消费者模式不能很好地扩展。你的生产者或消费者越多,你得到的性能就越差。原因是公共队列成为整个系统的瓶颈。我希望你能明白怎么做。
一种更好的方法是没有公共队列;让每个使用者都有自己的队列。当一个请求进入have时,它会转到负载均衡器。负载均衡器会将请求放在最小的消费者队列中。平衡器成为瓶颈,但它不会做太多操作-just选择正确的队列来发送传入的请求-因此它应该非常快。
这是一个编辑来回答你的问题:Problem (more in depth):你拥有的内核越多,它就变得越慢。为什么?共享内存。
@Peyman使用ConcurrentLinkedQueue (这是一个非阻塞等待自由队列,其中一个入队和一个出队可以同时进行)。甚至在您的初始设计中尝试它,并对两种设计进行基准测试。我希望你修改后的设计能有更好的表现,因为你可以同时只有1个入队和1个出队,而不是你最初的设计中的一个入队和n个出队(但这只是我的猜测)。
一个great paper on scalable consumer producer by using balancers
Read this page (或者只能查看“从公共工作队列方法迁移到每线程队列方法”)
这里有一个来自http://www.javaperformancetuning.com/news/newtips128.shtml的列表。我认为后三点更适用于你:
发布于 2012-03-18 14:32:41
编译正则表达式的速度很慢。对于给定的模式,您应该只执行一次。除非样例中显示的pattern变量对于每个调用都是不同的,否则Pattern实例可能是static类成员。Pattern对于多线程并发使用是明确安全的。(所有可修改状态都由Matcher保持。)
因为Matcher被限制在单个线程的堆栈中,所以您不需要担心任何线程问题。不要试图重用Matcher。这是可以做到的,但如果与regex编译相比,回收它们可以节省很多时间,我会感到惊讶。
发布于 2012-03-18 14:35:30
如果由于无法控制的同步而无法获得预期的并发性,那么您想到的一种解决方案是将工作分派给子进程(额外的JVM),最高可达核心数-1。
https://stackoverflow.com/questions/9756453
复制相似问题