Scala async vs. Java ForkJoinTask
Некоторое время назад я обнаружил Scala Async Project. Вопрос в том, что такое магическое в этом блоке async
, которое не может быть реализовано с помощью простых функций (без расширения макросов)?
Посмотрите на первый пример из введения:
import ExecutionContext.Implicits.global
import scala.async.Async.{async, await}
val future = async {
val f1 = async { ...; true }
val f2 = async { ...; 42 }
if (await(f1)) await(f2) else 0
}
Я не вижу ничего в приведенном выше примере, который не может быть написан в чистой Java. Этот код делает то же самое:
import java.util.concurrent.*;
import java.util.function.Supplier;
// First define a helper method for creating async blocks:
public static <T> ForkJoinTask<T> async(Supplier<T> supplier) {
return new RecursiveTask<T>() {
@Override
protected T compute() {
return supplier.get();
}
}.fork();
}
ForkJoinTask<Integer> future = ForkJoinPool.commonPool().submit(() -> {
ForkJoinTask<Boolean> f1 = async(() -> true);
ForkJoinTask<Integer> f2 = async(() -> 42);
if (f1.join()) {
return f2.join();
} else {
return 42;
}
});
Что может сделать Scala async
, что Java не может? Может быть, в случае более сложных сценариев? Что мне не хватает?
Ответы
Ответ 1
Существует одна важная разница в том, как два отрывка, которые вы опубликовали, работают под капотом: операции блокировки.
Фрагмент scala-async
примерно эквивалентен:
val future = {
val f1 = Future { ...; true }
val f2 = Future { ...; 42 }
f1.flatMap { b =>
if(b) f2 else Future.successful(0)
}
}
Это код на основе обратного вызова. Там нет операций, которые блокировали бы любой поток. Только регистрация в будущем и обратный вызов (что происходит при капоте flatMap
в этом случае). Другими словами, все там асинхронно.
С другой стороны, метод join
из пула fork-join Java блокирует поток.
Никакие операции блокировки не являются значительным преимуществом производительности/масштабируемости, потому что - значительно упрощает - нет блокировки = > меньше потребляемых потоков = > меньше ресурсов ОС или меньше переключения контекста.
Подведение итогов: целью scala-async
является сделать неблокируемую, основанную на обратном вызове асинхронную обработку как естественную в своем синтаксисе стандартного подхода блокировки (например, тот, который вы использовали в Java).