首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多线程Java正则表达式

多线程Java正则表达式
EN

Stack Overflow用户
提问于 2012-03-18 14:16:34
回答 3查看 3K关注 0票数 4

我有一个1生产者,M消费者线程模式。制作人从光盘中读取原始文档并将其放入LinkedBlockingQueue中。然后,每个使用者线程获取一个原始文档,并使用一个类解析该文档

代码语言:javascript
复制
ParsedDoc article = parseDoc(rawDocument);

parseDoc类是一组大约由20个方法组成的方法,其模式如下:

代码语言:javascript
复制
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个使用者之间是线程安全的。

任何帮助都将不胜感激

谢谢

EN

回答 3

Stack Overflow用户

发布于 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的列表。我认为后三点更适用于你:

  • 大多数服务器应用程序使用公共工作队列和线程池;共享工作队列保存来自远程源的短任务;线程池从队列中检索任务并处理这些任务;如果没有要处理的任务,则线程在队列上被阻塞。
  • 当任务数量很多而任务时间非常短时,线程之间共享的馈送队列是访问瓶颈(来自争用)。使用的内核越多,瓶颈就越严重。
  • 可用于在访问共享队列时克服争用的解决方案包括:使用无锁数据结构;使用具有多个锁的并发数据结构;维护多个队列以隔离争用。
  • 每线程队列方法消除了队列访问争用,但当一个队列被清空,而其他队列中有未处理的队列数据时,该方法并不是最佳的。为了改进这一点,空闲线程应该能够从其他队列中窃取工作。为了将争用保持在最小,应该从另一个队列的尾部进行“窃取”(从线程自己的队列中正常出队是从队列的头部完成的)。
票数 2
EN

Stack Overflow用户

发布于 2012-03-18 14:32:41

编译正则表达式的速度很慢。对于给定的模式,您应该只执行一次。除非样例中显示的pattern变量对于每个调用都是不同的,否则Pattern实例可能是static类成员。Pattern对于多线程并发使用是明确安全的。(所有可修改状态都由Matcher保持。)

因为Matcher被限制在单个线程的堆栈中,所以您不需要担心任何线程问题。不要试图重用Matcher。这是可以做到的,但如果与regex编译相比,回收它们可以节省很多时间,我会感到惊讶。

票数 2
EN

Stack Overflow用户

发布于 2012-03-18 14:35:30

如果由于无法控制的同步而无法获得预期的并发性,那么您想到的一种解决方案是将工作分派给子进程(额外的JVM),最高可达核心数-1。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9756453

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档