简体   繁体   English

ExecutorService - 并行运行任务并保存结果

[英]ExecutorService - running tasks in parallel and save results

I want to send a ping for up to 10 users at the same time, and update the user object with the result once the ping is done.我想同时向最多 10 个用户发送 ping,并在 ping 完成后用结果更新用户对象。

In order to do this, I am trying to use ExecutorService .为了做到这一点,我正在尝试使用ExecutorService

I started with a code like this:我从这样的代码开始:

private void pingUsers(List<User> userList) throws ExecutionException, InterruptedException {
    final int NUM_THREADS = 10;
    ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);

    for (User user : userList) {
        SnmpPingDevice pingUser = new PingUser(user);
        Future<Boolean> isUserActive = executor.submit(pingUser);
        user.isActive = isUserActive.get() ; // -- I guess it will block other pings and i'm back to my starting point where I need to run the pings in parallel.
    }

    executor.shutdown();
    try {
        executor.awaitTermination(30, TimeUnit.SECONDS);


    } catch (InterruptedException e) {
        logger.error("Failed to terminate executor");
    }
}

This is how my PingUser class look like:这是我的 PingUser 类的样子:

@Override
    public Boolean call() {
        ping = new CmdRunner(toolDir,outDir,
                new UserOidWorkerPing(version,community,ip,logger));

        return this.isActive();
    }

public boolean isActive(){
        String cmd = ping.getCmdNoRedirect(); 
        String rc = this.cmdRunner.runShellCmd(cmd,this.outDir +"/dummy",false);
        logger.debug("PING was sent with cmd:" + cmd + ",rc:" + rc);
        return rc != null && !rc.contains("Timeout:") && !rc.isEmpty();
    }

And back to the same issue, that the pings won't run in parallel (as soon as the loop waiting for the isUserActive.get() to end)回到同样的问题,ping 不会并行运行(只要循环等待isUserActive.get()结束)

Any idea what I'm missing?知道我错过了什么吗? How I can make those pings run in parallel and save the result for each user in my List<User> userList ?如何让这些 ping 并行运行并将每个用户的结果保存在我的List<User> userList

Future::get is a blocking operation so the invoking thread will be blocked until the call is completed. Future::get是一个阻塞操作,因此调用线程将被阻塞,直到调用完成。 So you submit a new task only after the previous was finished.所以你只有在上一个任务完成后才提交一个新任务。

Consider using ExecutorService::invokeAll which will return a list of Future s :考虑使用ExecutorService::invokeAll它将返回Future的列表:

List<PingUser> pingUsers = userList.stream().map(PingUser::new).collect(Collectors.toList());
List<Future<Boolean>> results = executor.invokeAll(pingUsers);

You are blocking your execution for each call, with this line:您使用以下行阻止了每次调用的执行:

user.isActive = isUserActive.get() ;

This effectively waits for the call to end, and does this for each call, on at a time.这有效地等待呼叫结束,并且一次对每个呼叫执行此操作。

You should rather submit all tasks, and build a list of Future s, to only wait for results when all tasks have been submitted.您应该提交所有任务,并构建一个Future列表,以便在所有任务都提交后才等待结果。 Something like this:像这样的东西:

List<Future<Boolean>> tasks = new ArrayList<>();
for (User user : userList) {
    SnmpPingDevice pingUser = new PingUser(user);
    tasks.add(executor.submit(pingUser));
}

for(Future<Boolean> task: tasks) {
    //use the result... OK to get() here.
}

What you can do is add the user.isActive = future.get() into the Runnable you submit.您可以做的是将user.isActive = future.get()到您提交的Runnable

for (User user : userList) {
    SnmpPingDevice pingUser = new PingUser(user);
    executor.submit(() -> user.isActive = pingUser.call());
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM