0

我的应用程序中有以下工作流程:可能有来自用户的 X 个请求(通常同时有 5-10 个)想要在系统中搜索某些内容(每个请求都在单独的线程中处理)。

每个搜索都可以并行处理(我目前正在实施)。线程/CPU 使用在这里并不是真正的问题,因为这些任务不是 CPU 密集型的。数据库是瓶颈。

目前我只为搜索机制设置了一个单独的数据库连接池 - 最大池大小设置为 10。我知道这并不多,但我不能将它设置得更高。现在我想弄清楚如何为每个搜索(每个用户)设置线程池。

每个请求(线程)都会产生一个单独的线程池(在这个池中每个线程将处理给定用户搜索的一部分)。如果例如 10 个用户一次点击“搜索”按钮,将这个线程池的大小设置为固定大小(假设为 4)真的会有问题,因为它会产生 10 个线程池,每个线程池有 4 个线程 = 40 个线程,并且只有 10 个池中的数据库连接?我猜有些线程只是空闲,其余线程会竞相获得池的连接,但这真的是一个大问题吗?

如果是,那么最好的做法是什么:

  1. 检查已经有多少线程池,同时创建一个新池并相应地调整其(这个新池的)最大线程池大小(假设已经有 2 个池,每个池有 4 个线程,那么将创建新的池,最大线程设置为 2甚至更新的池,可以说只有 1 个最大线程)。这将意味着每个下一个用户的搜索将大大变慢。
  2. 创建具有相同最大线程池大小(即 4)的线程池,但实现我自己的线程池,它将动态检查应用程序中有多少线程并相应地调整 maxThreadPoolSize 的大小(在这种情况下,例如所有线程池,2 个旧的和新的,将缩小到让我们说3线程)。这将要求每个线程池访问一些共享对象,其中包含有关应用程序中所有线程池的信息。
  3. 别的东西?

编辑: 感谢所有评论/答案。为了澄清为什么我想要每个请求都有一个线程池 - 这样做是为了让一个用户不会用完整个线程池。流程是这样的:当用户点击“搜索”时,会生成一个对象列表(这个列表可以从 1 个项目到数千个),然后为每个项目执行一个 DB 查找。现在这一切都是按顺序执行的。在我进行更改后,每个任务都会处理一次查找(因为在 DB 上的搜索速度非常慢,这给了我很大的提升——我知道我可以尝试做一些 DB 微调,但我不负责)。

问题是,如果我 User1 来并对 X 千生成的项目执行非常通用的搜索,则可能需要几分钟(或更长时间)。因此,我可以在单个用户的 executor 中执行数千个任务。然后,如果我有一个共享线程池,可以说最多 10 个线程(与连接池的数量相同),这个请求将被放入线程池的队列中。现在,如果 User2 来执行他的搜索,他将不得不等待 User1 的搜索完成,因为他的搜索将被放入同一个队列中。这是我想通过每个请求的线程池来避免的情况。

我并不是真的那么害怕上下文切换,因为每次计算可能需要几秒钟,所以它们不会经常发生。

目前我正在考虑一个共享线程池和一个管理器,每个用户线程都会将他的数据发送到该管理器,然后只要有空闲线程,该管理器就会将其发送到线程池。这样我就可以实现它(管理器)来发送来自不同用户的任务(即没有一个用户不会控制线程池)。

我用这种方法看到的问题是我需要以某种方式通知“父线程”(意思是用户请求)它的所有任务都由经理处理并以某种方式发送结果。

4

1 回答 1

1

现代处理器可以轻松处理数百个线程而没有问题,但正如@PeterLawrey 所暗示的那样,您的设计有些奇怪。如果如您所说,该操作在计算上并不昂贵,那么拥有非常多的线程将导致大量昂贵的上下文切换,从而导致性能下降。

额外的复杂性来自您希望每个请求都有一个线程池,而连接池是每个应用程序:

  • 如果每个请求都有一个线程池,则必须在每次收到新请求时创建并销毁它
  • 无论您将拥有数万亿个线程和预算为 100000 美元的超级计算机,都不会超过 10 个线程在做有用的工作。

您的直觉现在应该告诉您,问题在于您希望每个请求都有一个线程池,而理想的解决方案是在请求之间拥有一个共享线程池,线程数等于您的连接池大小。这将最大化线程重用。

如果您还想避免单个请求占用您所有的计算能力,您可能需要添加一个层来决定谁有权安排额外的工作。使用您考虑的每个请求的线程池解决方案,您让调度程序为您执行此操作,这不是一个好主意,因为您无法控制算法。

相反,您可以实现自己的“公平算法”,例如通过 PriorityBlockingQueue 将块数较少的项目放在顶部,或者使用 ConcurrentHashMap 为每个用户存储要安排的作业列表和已经完成的作业列表返回等等。

于 2012-08-09T13:39:27.687 回答