簡體   English   中英

從一批任務中部分檢索數據

[英]Partial retrieval of data from a batch of tasks

我正在使用ExecutorService提交一批任務。 我正在做這樣的事情:

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! 
}

這里的問題是-如果其中一項任務花費的時間超過2000ms,則將拋出TimeoutException ,盡管某些任務可能已在此時完成,但響應中我什么也得不到。

因此,我想檢索已完成的任務的響應(無論是部分響應還是完成響應),直到超時(2000毫秒)。 例如:

(相對於批處理調用的START_TIME的時間)
任務1:1000ms
任務2: 3000ms
任務3:1800ms


輸出:
超時異常


所需輸出:
好極了! <-對應於任務1
好極了! <-對應於任務3

我想到的一種解決方案是單獨獲取期貨並將其超時設置為MAX(0, TIME_OUT - TIME_NOW - START_TIME) 這可能有效,但對我來說似乎不是一個干凈的解決方案。

您可以使用裝飾可調用對象來處理超時。

假設這是原始可調用對象:

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

您可以使用此原始Callable和執行程序構造一個裝飾Callable:

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;
    }
}

如果決定使用此功能,則需要將池大小加倍:

Executors.newFixedThreadPool(threads * 2);

並在將它們放入最終結果集中之前添加諸如if(future.get() != null)類的條件。

如果使用Futures.getChecked,則會吞下超時異常,並且future將返回null。 簽出以下代碼,其中一項任務拋出TimeoutException,而相應的future返回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();
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM