Guava Futures.transform с «настоящим» исполнителем или transformAsync с DirectExecutor - PullRequest
0 голосов
/ 27 октября 2018

Скажем, у меня есть две тяжелые операции блокировки ввода-вывода, findMatchInSomeDB () и getDetailsFromOtherDB (String objectKey). Кроме того, я хочу, чтобы они работали в фоновом режиме и использовали Guava Futures, чтобы связать их вместе, потому что один зависит от результата другого (я знаю, что это можно было бы просто сделать последовательно в простом Callable, но сделать его простым для иллюстративные цели) :

Есть ли практическая или нюансированная разница между consumeChain и consumeChainAsync методами ниже?

import com.google.common.base.Function;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;

public class Consumer
{
   private final Retriever retriever;
   private final ListeningExecutorService executorSvc;

   public Consumer(Retriever retriever, ListeningExecutorService executorSvc)
   {
      this.retriever = retriever;
      this.executorSvc = executorSvc;
   }

   private void consumeChain(String searchCriteria) throws Exception
   {
      ListenableFuture<String> futureMatch = executorSvc.submit(
         () -> retriever.findMatchInSomeDB(searchCriteria));

      Function<String, DataObject> keyToDataObj = objectKey ->
         retriever.getDetailsFromOtherDB(objectKey);

      // using "real" executor service so transform function runs
      // in the background
      ListenableFuture<DataObject> futureDataObj = Futures.transform(
         futureMatch, keyToDataObj, executorSvc);

      // ...do some other stuff in this thread...

      // do something with futureDataObj result
      futureDataObj.get();
   }

   private void consumeChainAsync(String searchCriteria) throws Exception
   {
      ListenableFuture<String> futureMatch = executorSvc.submit(
         () -> retriever.findMatchInSomeDB(searchCriteria));

      AsyncFunction<String, DataObject> keyToDataObj = objectKey ->
      {
         return executorSvc.submit(
            () -> retriever.getDetailsFromOtherDB(objectKey));
      };

      // using DirectExecutor because the transform function
      // only creates and submits a Callable
      ListenableFuture<DataObject> futureDataObj = Futures.transformAsync(
         futureMatch, keyToDataObj, MoreExecutors.directExecutor());

      // ...do some other stuff in this thread...

      // do something with futureDataObj
      futureDataObj.get();
   }
}

Насколько я могу судить, обе будут выполнять каждую тяжеловесную операцию через executorSvc, и обе будут распространять отмену и / или сбой выполнения.

Кажется, что единственная точка transformAsync (вместо простого использования transform с исполнителем, отличным от DirectExecutor) - это когда вы работаете с API, который возвращает ListenableFuture вместо непосредственного выполнения операции. Я что-то упустил?

1 Ответ

0 голосов
/ 03 января 2019

Кажется, что единственная точка transformAsync (вместо простого использования transform с исполнителем, отличным от DirectExecutor) - это когда вы работаете с API, который возвращает ListenableFuture вместо прямого запуска операции.

Я думаю, что это идея.

Однако я могу вспомнить небольшую разницу, которая делает transformAsync немного лучше: если вы вызываете cancel(true) на выходе Future, transform в настоящее время не будет прерывать поток, который запускает getDetailsFromOtherDB.Напротив, transformAsync будет (вызывая cancel(true) на ListenableFuture, возвращенном из ListeningExecutorService).transform должен распространять прерывание, но есть некоторые тонкости для получения этого права, описанные в ссылке выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...