长期以来,异步处理是我感兴趣的主题之一。 我看到了很多有关该主题的文章,但是我较新的文章看到了(至少简短地)涵盖了大多数文章。 我决定尝试填补这一空白。 下面的描述非常简短,但是尝试至少显示每个模型的基本属性。
Callbacks
This one is, probably one of the oldest and probably most widely used. The idea is obvious - configure callback functions (often called handler) and it will be called when request arrives or some other event happens. There are a lot of uses of this model. Probably most famous one are earlier versions of Node.js. In Java world, older versions of Vert.x is a great example of this model.
在代码中,此模型通常类似于以下内容:
... // Prepare request
request.send(asyncResult -> {
if (asyncResult.succeeded()) {
System.out.println(asyncResult.result().body().getString("joke"));
}
});
Lambda传递给请求发送是一个回调函数,当收到请求响应时调用。
尽管此模型看起来很简单,但是它有一个巨大的缺点-回调是不可组合的。 例如,没有简单的方法来创建将在触发其他两个回调时调用的回调。 结果,任何或多或少的复杂处理都会迅速变成回调地狱。
Reactive Streams
This model is quite popular: implementations like RxJava, Project Reactor, Reactive Streams are widely used.
该模型背后的思想是:传入事件/请求/数据/等的每个来源。 表示为流,然后将处理组装为处理该流中元素的管道。 管道可能非常复杂,并且可以由不同的流组成。
该代码通常如下所示:
Observable.fromIterable(words)
.zipWith(Observable.range(1, Integer.MAX_VALUE),
(string, count)->String.format("%2d. %s", count, string))
.subscribe(System.out::println);
此模型非常强大且方便。 但是,复杂的处理流可能需要一些时间来掌握,而且并不总是很容易掌握。 另一个缺点是每个数据源(包括单个值)都应表示为流。 这通常看起来是虚假的。
Future
的未来表示可能尚不可用,但最终可用的结果:
Future<Result> futureResult = executor.submit(() -> new Result("success"));
Future is composable (although requires quite a lot of ceremony ) but it's far from convenient. If you need to know when result is ready, you have no choice but just convert asynchronous processing into synchronous one by calling Future.get()
.
Promises
在高层承诺可以认为是期货和回叫。 什么时候诺言 is get resolved (assigned value) 回叫 are invoked automatically:
...
Promise<User> getUserById(UUID userId);
...
getUserById(userId)
.then(user -> System.out.println("User: " + user));
...
回调函数传递给。然后()方法将在以下时间被调用诺言将得到解决。 可以添加到的回调数量没有限制诺言,因此当实例通过各种方法传递时,它们可以根据需要添加自己的回调。 如果诺言在添加新的回调时已经解决,该回调将立即被调用。 每个回调仅被调用一次,并且仅在一个线程的上下文中被调用,因此无需担心同步问题。
承诺都是可组合的,代码的编写和读取非常简单。 也没有人为表示数据。
These properties of Promises triggered (slow) switching to them in recent versions of Vert.x, although they look somewhat foreign there because callback-based API remains mostly unchanged, so Promises are just wrappers for callbacks.
还有一个实现承诺自Java 8起就存在于JDK中,并称为未来发展。 必须承认,这种实现方式不能直接替代传统的承诺-它非常重量级,并且具有不方便的API。
Instead of afterword
At present I'm working on the library which implements Promises model in more lightweight and convenient to use form.
To get a taste how code utilizing this library might look like:
public Promise<Either<? extends BaseError, UserDashboard>> userProfileHandler(final UUID userId) {
return zipAll(userService.userProfile(userId),
userService.followers(userId),
articleService.articlesByUser(userId, Order.DESC),
commentService.commentsByUser(userId, Order.DESC))
.map(result -> result.mapSuccess(tuple -> tuple.map(UserDashboard::new)));
}
上面的代码只是一个示例,库本身具有版本0.1.0,但已经可以使用当前状态的库以这种方式编写代码。