Как использовать Akka Futures асинхронно в Java

Я делаю вызов на уровне службы Java, который выглядит следующим образом;

Future<Object> future = Patterns.ask(myActor, message, timeout);

Response res = (Response) Await.result(future, timeout.duration());

Я прочитал документацию Akka и понимаю, что такая блокировка не рекомендуется. Мне нужно вернуть объект ответа вызывающему методу. Можно ли сделать это асинхронно с Akka из моей службы Java? Я попытался сделать это с помощью метода future.onSuccess, однако метод onSuccess не позволяет возвращать значение, поэтому я не могу вернуть значение.


person cdugga    schedule 20.08.2014    source источник


Ответы (1)


Акка-способ передачи данных между потоками, который, по сути, является тем, что вы делаете путем блокировки выше, - это составление фьючерсов или отправка сообщения Актеру.

Следующий пример взят из документации Akka.

final ExecutionContext ec = system.dispatcher();

Future<String> f1 = future(new Callable<String>() {
    public String call() {
        return "Hello" + "World";
    }
}, ec);

Future<Integer> f2 = f1.map(new Mapper<String, Integer>() {
    public Integer apply(String s) {
        return s.length();
    }
}, ec);

f2.onSuccess(new PrintResult<Integer>(), system.dispatcher());

Обратите внимание, что в этом примере данные «возвращаются», или, точнее, они передаются другой единице работы без необходимости блокировать поток и ждать результата.

Вот почему onSuccess возвращает void, он должен использоваться в конце цепочки составленных фьючерсов. Если бы он должен был вернуть значение, это было бы как map, и он вернул бы другое Future. Что оставило бы вас с тем же требованием блокировки.

Таким образом, чтобы ответить на ваш вопрос, нет. Невозможно «вернуть» значение из асинхронного будущего без блокировки. Вместо этого вы должны понять, почему вам нужно, чтобы Response возвращался таким образом, и посмотреть, можете ли вы вместо этого переместить обработку Response в onSuccess или map. Незначительная альтернатива - вернуть Future [Response] и позволить вызывающей стороне беспокоиться о связывании фьючерсов. Случай, с которым вы столкнулись, обычно случается при смешивании парадигм, и его лучше избегать.

person Chris K    schedule 20.08.2014
comment
вызов, который блокируется, инициируется, когда пользователь обращается к услуге на моем веб-сайте. Я блокирую поток, потому что хочу, чтобы ответ на запрос содержал некоторые данные для обновления пользовательского интерфейса. Как бы вы порекомендовали мне это сделать? - person cdugga; 21.08.2014
comment
Код графического интерфейса @cdugga в любом случае обычно разрабатывается вокруг продолжений / обратных вызовов, поэтому эта часть должна быть простой. Уловка обычно заключается в сетевой части; если сетевой код спроектирован как асинхронный (с использованием фьючерсов и nio под капотом), то бинго. В противном случае у вас нет выбора, вы должны заблокировать, и это то, что я имел в виду, говоря о парадигмах микширования. Большая часть сетевого кода Java спроектирована на основе старой школы, содержащей одну потоковую и блочную модель, и когда этот тип кода смешивается с Akka, тогда нужно где-то блокировать. Просто постарайтесь минимизировать его и оставить в одном или двух местах. - person Chris K; 21.08.2014
comment
@cdugga, когда я работаю с клиентами, у которых есть этот тип кода, и база кода слишком велика, чтобы перейти на полностью асинхронное решение за один раз, я обычно начинаю с самого нижнего уровня и начинаю изменять DAO и т.д., возвращая DTO в будущее [DTO]. Когда этот интерфейс переходит в неасинхронную область, возникает блок. Со временем я подталкиваю его все выше и выше, пока он не достигнет сетевого кода, а затем последний шаг - заменить сетевую библиотеку на асинхронную. - person Chris K; 21.08.2014
comment
@cdugga другая возможность, которая часто встречается, - это когда вызов db или webservice использует блокирующий api; в этом случае можно использовать Future или Actor для обертывания этого api, и ему может быть назначен единственный поток вне глобального пула потоков Akka. Таким образом, API-интерфейс блокировки выглядит неблокирующим для Akka и позволяет избежать загрязнения глобального пула потоков, которое может привести к снижению производительности в противном случае быстрых фьючерсов, а в экстремальных случаях Akka может заблокироваться. - person Chris K; 21.08.2014