4 ms·
I don't understand how this is different from the standard RPC model. A typical RPC in a C++/Java/C# language looks something like this: var client = EchoCl
by jmillikin 13y ago
I don't understand how this is different from the standard RPC model.
A typical RPC in a C++/Java/C# language looks something like this:
var client = EchoClient::Connect("corba://example.com:9000");
var request = new EchoRequest();
request.set_message("hello world!")
var options = new RpcOptions();
options.set_timeout_milliseconds(5000);
Future<EchoResponse> futureResponse = client.Echo(request, options);
EchoResponse response = futureResponse.Wait();
According to the article this is going "back in time", but that's completely silly -- the response is being returned at the point of the Wait() call, which blocks until the server has finished RPC processing.
And of course, languages with proper thread support (e.g. Haskell) don't need to bother with futures at all, because it's easy to spawn a new thread for each request instead of blocking some central main thread.
And it's fairly easy to provide syntactic sugar over this to provide closure-based control flow
- kentonv 13y agoWhere does that code come from? That's not Cap'n Proto. Sorry, but did you read the docs?
- jmillikin 13y agoThat's the kind of code that would be used in a typical RPC system written in the last ~20 years. You have some sort of client stub, a request object, and a response handle that has operations for waiting until the server has generated the response. The actual marshaling implementation could be ASN.1 or JSON or Thrift or whatever the local programmers want. I want to know how the Cap'n'proto design discussed in the post is significantly different from this standard RPC model.
- philjohn 13y agoIf you're executing a 2nd procedure call that uses the output of the first (or 3rd, 4th 5th etc) then it requires 1 call. A traditional RPC system would either need a combined method (which is suboptimal from a "clean design" perspective) or you'd get the response of the 1st back, and then just pass it back to the server for the 2nd call.
- jmillikin 13y agoSo the major improvement described here is a hint to the server that it should pass the response from one RPC directly into the request of another, rather than returning anything to the client? That seems like it'd only be useful in very specific circumstances; you'd need RPC methods with the same type for request and response, and it only works if you're using the same backend for each call (e.g. you can't have load balancing of separate calls).
- kentonv 13y agoIf you read the documentation, I give an extended argument for why this is useful: it enables more object-oriented protocol design. http://kentonv.github.io/capnproto/rpc.html http://kentonv.github.io/capnproto/rpc.html Also, it is not the case that the new RPC's input type has to match the old one's output. You can take just one object embedded in the old response and use it in the new request. Please do look at the examples.
- kentonv 13y agoCap'n Proto's RPC interface is different. The call returns a promise (like a future), but you don't have to wait on it. The promise itself has methods that let you do things with the results, such as call them or use them in the parameters to other calls that go back to the server. These chained calls can be sent to the server before the initial call completes, by just telling the server "When the previous call completes, do this with the result". This is all described in detail in the docs. http://kentonv.github.io/capnproto/rpc.html http://kentonv.github.io/capnproto/rpc.html
- pkinsky 13y agoScala uses the Future monad pretty widely to model concurrency. Does Haskell not use the Future monad? What does it use instead?
- jmillikin 13y agoIn Haskell it'd be more typical to use blocking operations for RPCs and spawn a thread for each sequence. For example, the article has a sequence of operations that should be run in order; that would be a single thread, with each operation blocking until it's ready. If some operations need to be async, then spawn another thread for just that operation. This model is possible because the Haskell runtime decouples threads from the OS's process-with-shared-address-space abstraction, so running a few million threads is a reasonable design choice. Users of Erlang will find the Haskell threading model very familiar, with the exception that Haskell also provides ways to pass around mutable state (e.g. you could pass a pointer through a channel). It is possible to implement something like a Future monad if you really want to, based on MVar, but cheap threads make it unnecessary.