循环消息/任务队列现有解决方案

时间:2018-06-14 08:32:33

标签: java architecture task message-queue

考虑一组有限的任务必须在一段时间内完成(在这段时间内均匀分布),然后一再重复。

如果是一个本地工作者/线程,我们只是做这样的事情(抱歉伪代码):

long interval = period / tasks.size

while (true) {
  for (task in tasks) { 
    task.do()
    sleep(interval)
  }
}

现在我想以分布式方式,多个独立工作人员这样做。

对于这样的案例,是否有一些已知的最佳实践解决方案(最好是来自Java世界)?循环消息队列?分布式锁定任务?我已经谷歌搜索了一下,但是看不到任何优雅的开箱即用解决方案。

3 个答案:

答案 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。