【问题标题】:Executor Service and Huge IO执行器服务和巨大的 IO
【发布时间】:2015-10-17 11:40:57
【问题描述】:

我有一个服务,它调用数据库并对每个结果执行回调。

ExecutorService service = Executors.newFixedThreadPool(10);
service.exectute(runnable(segmentID, callback)); // database is segmented

可运行的是:

call database - collect all the rows for the segment keep in memory
perform callback(segment);

现在的问题是我得到了数据库返回的大量行,我的理解是执行程序服务将在线程空闲时调度线程 I/O。所以我进入了内存不足。

有没有什么办法可以限制一次只运行10个线程并且不进行executor服务调度?

出于某种原因,我必须将段的所有行保留在内存中。 我怎样才能通过这样做来防止OOM。 Executor 服务 newFixedThreadPool 解决方案吗?

如果我遗漏了什么,请告诉我。

谢谢

【问题讨论】:

  • 一些未知代码做未知的事情会导致内存问题。很难帮上忙。发布您的代码。向我们展示您如何“调用数据库”。向我们展示回调的作用。
  • 请假设我想在 runnable 中执行巨大的 IO 并将检索到的值保存在内存中。如果我说有 10 个线程在执行 IO,而其他线程处于空闲状态,我不会进入 OOM,但如果执行器服务在这 10 个正在执行 IO 时调度其他线程,那么我肯定会进入 OOM。
  • 如果您将 10 个或更多任务提交给有 10 个可用线程的执行器,则这 10 个线程并发执行。这就是重点。如果您只希望 2 个线程并行执行,则创建一个具有 2 个线程的执行器。但无论如何,如果任务完成后所有内容都保留在内存中,那么线程数不会改变任何内容。

标签: java multithreading concurrency executorservice


【解决方案1】:

您必须使用固定的线程池。有一条规则,您应该只生成 N 个线程,其中 N 应该与 CPU 中的内核数处于同一数量级。关于 N 的大小存在争议,您可以阅读更多关于它的信息here。对于普通的 CPU,我们可以说 4,8,16 个线程。

但是,即使您在集群中运行程序(我认为您不是),您也不能只从数据库中获取 20k 行并假装生成 20k 线程。如果这样做,您的应用程序的性能将会大幅下降,因为大部分 CPU 周期将用于上下文切换。

现在即使使用固定的线程池,如果获取的数据同时存储在内存中,您也可能会遇到 OOM 异常。我认为唯一的解决方案是获取较小的数据块,或者在下载数据时将数据写入文件。

【讨论】:

  • 链接问题中接受的答案以“如果您的线程不执行 I/O,...”开头。这里的问题是关于“巨大的 IO”,至少在标题中是这样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-16
  • 2013-08-08
  • 1970-01-01
  • 1970-01-01
  • 2017-01-03
  • 2017-03-13
相关资源
最近更新 更多