Mercurial > hg > sv-dependency-builds
diff src/capnproto-git-20161025/doc/_posts/2013-12-13-promise-pipelining-capnproto-vs-ice.md @ 133:1ac99bfc383d
Add Cap'n Proto source
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Tue, 25 Oct 2016 11:17:01 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-git-20161025/doc/_posts/2013-12-13-promise-pipelining-capnproto-vs-ice.md Tue Oct 25 11:17:01 2016 +0100 @@ -0,0 +1,76 @@ +--- +layout: post +title: "Promise Pipelining and Dependent Calls: Cap'n Proto vs. Thrift vs. Ice" +author: kentonv +--- + +_UPDATED: Added Thrift to the comparison._ + +So, I totally botched the 0.4 release announcement yesterday. I was excited about promise +pipelining, but I wasn't sure how to describe it in headline form. I decided to be a bit +silly and call it "time travel", tongue-in-cheek. My hope was that people would then be +curious, read the docs, find out that this is actually a really cool feature, and start doing +stuff with it. + +Unfortunately, [my post](2013-12-12-capnproto-0.4-time-travel.html) only contained a link to +the full explanation and then confusingly followed the "time travel" section with a separate section +describing the fact that I had implemented a promise API in C++. Half the readers clicked through +to the documentation and understood. The other half thought I was claiming that promises alone +constituted "time travel", and thought I was ridiculously over-hyping an already-well-known +technique. My HN post was subsequently flagged into oblivion. + +Let me be clear: + +**Promises alone are _not_ what I meant by "time travel"!** + +<img src='{{ site.baseurl }}images/capnp-vs-thrift-vs-ice.png' style='width:350px; height:275px; float: right;'> + +So what did I mean? Perhaps [this benchmark](https://github.com/kentonv/capnp-vs-ice) will +make things clearer. Here, I've defined a server that exports a simple four-function calculator +interface, with `add()`, `sub()`, `mult()`, and `div()` calls, each taking two integers and\ +returning a result. + +You are probably already thinking: That's a ridiculously bad way to define an RPC interface! +You want to have _one_ method `eval()` that takes an expression tree (or graph, even), otherwise +you will have ridiculous latency. But this is exactly the point. **With promise pipelining, simple, +composable methods work fine.** + +To prove the point, I've implemented servers in Cap'n Proto, [Apache Thrift](http://thrift.apache.org/), +and [ZeroC Ice](http://www.zeroc.com/). I then implemented clients against each one, where the +client attempts to evaluate the expression: + + ((5 * 2) + ((7 - 3) * 10)) / (6 - 4) + +All three frameworks support asynchronous calls with a promise/future-like interface, and all of my +clients use these interfaces to parallelize calls. However, notice that even with parallelization, +it takes four steps to compute the result: + + # Even with parallelization, this takes four steps! + ((5 * 2) + ((7 - 3) * 10)) / (6 - 4) + (10 + ( 4 * 10)) / 2 # 1 + (10 + 40) / 2 # 2 + 50 / 2 # 3 + 25 # 4 + +As such, the Thrift and Ice clients take four network round trips. Cap'n Proto, however, takes +only one. + +Cap'n Proto, you see, sends all six calls from the client to the server at one time. For the +latter calls, it simply tells the server to substitute the former calls' results into the new +requests, once those dependency calls finish. Typical RPC systems can only send three calls to +start, then must wait for some to finish before it can continue with the remaining calls. Over +a high-latency connection, this means they take 4x longer than Cap'n Proto to do their work in +this test. + +So, does this matter outside of a contrived example case? Yes, it does, because it allows you to +write cleaner interfaces with simple, composable methods, rather than monster do-everything-at-once +methods. The four-method calculator interface is much simpler than one involving sending an +expression graph to the server in one batch. Moreover, pipelining allows you to define +object-oriented interfaces where you might otherwise be tempted to settle for singletons. See +[my extended argument]({{ site.baseurl }}rpc.html#introduction) (this is what I was trying to get +people to click on yesterday :) ). + +Hopefully now it is clearer what I was trying to illustrate with this diagram, and what I meant +by "time travel"! + +<img src='{{ site.baseurl }}images/time-travel.png' style='max-width:639px'>