考虑一组有限的任务必须在一段时间内完成(在这段时间内均匀分布),然后一再重复。
如果是一个本地工作者/线程,我们只是做这样的事情(抱歉伪代码):
long interval = period / tasks.size
while (true) {
for (task in tasks) {
task.do()
sleep(interval)
}
}
现在我想以分布式方式,多个独立工作人员这样做。
对于这样的案例,是否有一些已知的最佳实践解决方案(最好是来自Java世界)?循环消息队列?分布式锁定任务?我已经谷歌搜索了一下,但是看不到任何优雅的开箱即用解决方案。
答案 0 :(得分:4)
我认为没有唯一的“最佳”方法,因为这将在灵活性和均匀性保证的强度之间进行权衡。
在灵活的范围内,只需在此期间的某个时间将每个任务随机分配给工人即可。这将不需要工作人员之间的通信,因此这是可伸缩和可并行的。您会期望事情应该是相当均匀的,尤其是在您有很多任务的情况下。
在频谱的强均匀性末端,应按@Lino所示按任务和时隙划分任务。这将需要您事先知道您有多少工人等,并且这是不可并行的。
在这两种极端之间有许多替代方法,以及混合方法。
要缩小答案的范围,您需要提供有关限制条件和成功标准的更多详细信息。
答案 1 :(得分:2)
下面,我只是转储了想出的代码。我试图评论我所做的每一步。简而言之,它只是将所有任务的工作负载平均分配给所有可用的工作人员。并计算在给定的毫秒数内完成所有任务的等待时间
// the tasks we want to execute
final List<Runnable> tasks = Arrays.asList(
() -> System.out.println("First"),
() -> System.out.println("Second"),
() -> System.out.println("Third"),
() -> System.out.println("Fourth")
);
// amount of threads
final int amountOfWorkers = 2;
// period in milliseconds
final int period = 1000;
// caching the size for multiple use
final int tasksSize = tasks.size();
// calculating the workload of each worker
final int workLoad = (int) Math.ceil((double) tasksSize / amountOfWorkers);
// interval of sleep for each worker
final int workerPeriod = period / workLoad;
// a list of all workers
final List<Thread> workers = new ArrayList<>();
// in this for loop we create each worker and add it to above list
for(int i = 0; i < amountOfWorkers; i++){
// calculating the start of the sublist
final int startIndex = i * workLoad;
// calculating the end of the sublist
final int endIndex = (i + 1) * workLoad;
// here we create the subTasks for each worker, we need to take into account that the tasksList may not
// divide fully. e.g. 7 for 4 workers leaves the last worker with only one task
final List<Runnable> subTasks = tasks.subList(startIndex, endIndex < tasksSize ? endIndex : tasksSize);
// creating the worker itself
final Thread worker = new Thread(() -> {
for(final Runnable subTask : subTasks){
try{
subTask.run();
Thread.sleep(workerPeriod);
} catch(InterruptedException e){
throw new IllegalStateException(e);
}
}
});
// add it to our worker list
workers.add(worker);
// and start it
worker.start();
}
// at last we wait in the main thread for all workers to finish
for(final Thread worker : workers){
worker.join();
}
这当然可以放到一个类中,该类接受输入参数,例如:
哪个会更加面向对象。如果需要的话,我也可以提供该代码,但是上面应该给您一个大概的想法。
答案 2 :(得分:-1)
您可以像这样用Java-8流运行stream.paralle():
List<Task> tasks = new ArrayList<>();
Stream.of(tasks).parallel().forEach(t -> t.doSomething());
这将为您使用所有CPU资源。
如果您需要类似群集的解决方案,即通过网络运行,您可以选择不同的选项,但是它们都涉及一些框架。
我个人更喜欢Vert.x,因为它很容易设置集群,并且使用事件总线可以分配工作量。其他简单的选择是Spring。