【发布时间】:2018-02-05 22:32:28
【问题描述】:
我正在开发一个 Web 应用程序,该应用程序为其用户提供可选的“在后台”执行长时间运行的进程。一个示例是生成一些长时间运行的报告,或同时删除数千个对象。
我已经使用 ExecutorService 实现了这个,它使用 ThreadFactory 定义为 FixedThreadPool。 ThreadFactory 是这样构建的:
ThreadFactoryBuilder()
.setNameFormat(clientId + "-BackgroundTask-%d")
.setDaemon(true)
.setPriority(Thread.MIN_PRIORITY)
.build()
我这样执行任务:
Future<TaskStatus> future = clientExecutors.get(clientId).submit(
backgroundTask::execute);
taskFutures.put(backgroundTask.getTaskId(), future);
如何强制我的网络服务器始终优先处理新的传入请求(尽可能快)而不是执行后台任务?
换句话说:永远不会发生用户在浏览网站时必须等待很长时间,因为有很多后台任务正在执行。从上面可以看出,我尝试通过设置.setPriority(Thread.MIN_PRIORITY) 来做到这一点。然而,这似乎还不够。
此外,就目前而言,我已经为 FixedThreadPool 大小 (10) 设置了一些任意值,并在全局范围内将其用于应用程序(及其所有客户)的整个后台处理。
相反,我想为每个客户定义一个线程池,以确保每个客户都有相同的权限在后台运行一定数量的任务。比如说,每个客户都有一个大小为 5 的 FixedThreadPool,在服务器上我会有一个最大值。 50 个不同的客户。这将同时添加多达 250 个正在运行的后台任务。
这里最重要的要求是:这些后台任务需要执行多长时间(比如 2 分钟或 20 分钟)并不重要。重要的是,每个客户都可以发送 5 个任务在后台执行,并且每个任务都平等地处理。
我已经测试了运行 30 个 CPU 密集型后台任务,结果表明,虽然这些任务正在运行并且 cpu 接近 100%,但新的传入请求需要很长时间才能处理。
很明显,我做错了。
12.09.2017 更新 我读过微服务,虽然听起来不错,但我发现从我们的单体应用程序中分离必要的部分是一个巨大的挑战。主要是因为给定足够大的数据选择,几乎每个操作都可能变成一个长时间运行的过程。 此外,我的微服务不会遇到同样的问题,即运行微服务的服务器会遭受同样的性能下降。好吧,唯一的好处是,Web 应用程序的其余部分将不再受此影响。
我已经阅读了一些关于将 Thread.sleep(1) 或 Thread.sleep 引入 CPU 密集型操作的文章,以减少这些操作中使用的 CPU 量。我还读到有人将其作为一个方面引入,以便他甚至可以动态更改等待的时间量,以便对使用多少 cpu 进行一些控制。
但是,我的直觉告诉我这也不对。您如何看待引入 Thread.sleep 以降低用于任务的 CPU 量?这是常见的做法吗?如果不是,那么正确的方法是什么?
【问题讨论】:
标签: spring multithreading tomcat asynchronous aop