简体   繁体   中英

Partial retrieval of data from a batch of tasks

I'm using ExecutorService for submitting a batch of tasks. I'm doing it something like this:

ListeningExecutorService exec = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(threads));
List<ListenableFuture<Whatever>> futures = new ArrayList<>();
for (int i = 0; i < 100; i++) {
  results.add(exec.submit(new MyTask(i)));
}

ListenableFuture<List<Whatever>> listListenableFuture = Futures.successfulAsList(futures);

try {
    List<Whatever> responses = listListenableFuture.get(2000, TimeUnit.MILLISECONDS);
    for (Whatever response : responses) {
      LOG.info("Yay!");
    }
} catch (TimeoutException e) {
  LOG.info("Timeout Exception");
} catch (Exception e) {
  // Nay! 
}

The problem here is - if one of the task takes longer than 2000ms, will throw the TimeoutException and I'll get nothing in the response though some of the tasks might have finished at that very point.

So I want to retrieve the response (be it partial or complete) of the tasks that have been finished till it timeouts (2000ms). Eg:

(time relative to the START_TIME of the batch call)
Task-1: 1000ms
Task-2: 3000ms
Task-3: 1800ms



Timeout Exception



Yay! <- corresponds to task-1
Yay! <- corresponds to task-3

One solution I thought of is to fetch the futures individually and set their timeout as MAX(0, TIME_OUT - TIME_NOW - START_TIME) . This might work but doesn't seems like a clean solution to me.

You might use a decorate callable which handles the time out.

Suppose this is the original callable:

class OriginalCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "";
    }
}

You can construct a decorate callable with this original callable and the executor:

class DecorateCallable implements Callable<String> {
    ExecutorService executorService;
    OriginalCallable callable;

    public DecorateCallable(ExecutorService executorService, OriginalCallable callable) {
        this.executorService = executorService;
        this.callable = callable;
    }

    @Override
    public String call() throws Exception {
        Future<String> future = executorService.submit(callable);
        try {
            return future.get(2000, TimeUnit.SECONDS);
        } catch (TimeoutException | InterruptedException e) {

        }
        return null;
    }
}

If you decide to use this, you need double you pool size:

Executors.newFixedThreadPool(threads * 2);

and add some condition like if(future.get() != null) before put them into the final result set.

If you use Futures.getChecked, the timeout exceptions get swallowed, and the future will return null. Check out the following code, where one of the tasks throws TimeoutException, and the corresponding future returns null.

import java.io.IOException;

import com.google.common.util.concurrent.*;
import java.time.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;

public class App 
{
    public static void main( String[] args ) throws InterruptedException, ExecutionException
    {
        ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));
        ListenableFuture<String> future1 = 
            listeningExecutorService.submit(() -> {
                throw new TimeoutException("Timeout exception");
            });
        ListenableFuture<String> future2 = 
            listeningExecutorService.submit(() -> "Hello World");
        ListenableFuture<List<String>> combined = Futures.successfulAsList(future1, future2);
        try {
            String greeting = Futures.getChecked(combined, IOException.class, 2000l, TimeUnit.MILLISECONDS).stream().collect(Collectors.joining(" "));
            System.out.println(greeting);
        } catch (IOException e) {
            System.out.println("Exception: " + e.getMessage());
        } finally {
            listeningExecutorService.shutdown();
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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