39a1aa81c7592803f39da459b2a241277aca5bd5
[folly.git] / folly / futures / README.md
1 # folly::Futures
2
3 Futures is a futures-based async framework inspired by [Twitter's Finagle](http://twitter.github.io/finagle/) (which is in scala), and (loosely) building upon the existing (but anemic) Futures code found in the C++11 standard ([`std::future`](http://en.cppreference.com/w/cpp/thread/future)) and [`boost::future`](http://www.boost.org/doc/libs/1_53_0/boost/thread/future.hpp) (especially >= 1.53.0). Although inspired by the std::future interface, it is not syntactically drop-in compatible because some ideas didn't translate well enough and we decided to break from the API. But semantically, it should be straightforward to translate from existing std::future code to Futures.
4
5 The primary semantic differences are that folly's Futures and Promises are not threadsafe; and as does `boost::future`, folly::Futures support continuing callbacks (`then()`) and there are helper methods `whenAll()` and `whenAny()` which are important compositional building blocks.
6
7 ## Brief Synopsis
8
9 ```C++
10 #include <folly/futures/Future.h>
11 using namespace folly;
12 using namespace std;
13
14 void foo(int x) {
15   // do something with x
16   cout << "foo(" << x << ")" << endl;
17 }
18
19 // ...
20
21   cout << "making Promise" << endl;
22   Promise<int> p;
23   Future<int> f = p.getFuture();
24   f.then(
25     [](Try<int>&& t) {
26       foo(t.value());
27     });
28   cout << "Future chain made" << endl;
29
30 // ... now perhaps in another event callback
31
32   cout << "fulfilling Promise" << endl;
33   p.setValue(42);
34   cout << "Promise fulfilled" << endl;
35 ```
36
37 This would print:
38   
39 ```
40 making Promise
41 Future chain made
42 fulfilling Promise
43 foo(42)
44 Promise fulfilled
45 ```
46
47 ## User Guide
48
49 Let's begin with an example. Consider a simplified Memcache client class with this interface:
50
51 ```C++
52 class MemcacheClient {
53  public:
54   struct GetReply {
55     enum class Result {
56       FOUND,
57       NOT_FOUND,
58       SERVER_ERROR,
59     };
60
61     Result result;
62     // The value when result is FOUND,
63     // The error message when result is SERVER_ERROR or CLIENT_ERROR
64     // undefined otherwise
65     std::string value;
66   };
67
68   GetReply get(std::string key);
69 };
70 ```
71
72 This API is synchronous, i.e. when you call `get()` you have to wait for the result. This is very simple, but unfortunately it is also very easy to write very slow code using synchronous APIs.
73
74 Now, consider this traditional asynchronous signature for `get()`:
75
76 ```C++
77 int get(std::string key, std::function<void(GetReply)> callback);
78 ```
79
80 When you call `get()`, your asynchronous operation begins and when it finishes your callback will be called with the result. (Unless something goes drastically wrong and you get an error code from `get()`.) Very performant code can be written with an API like this, but for nontrivial applications the code descends into a special kind of spaghetti code affectionately referred to as "callback hell".
81
82 The Future-based API looks like this:
83
84 ```C++
85 Future<GetReply> get(std::string key);
86 ```
87
88 A `Future<GetReply>` is a placeholder for the `GetReply` that we will eventually get. A Future usually starts life out "unfulfilled", or incomplete, i.e.:
89
90 ```C++
91 fut.isReady() == false
92 fut.value()  // will throw an exception because the Future is not ready
93 ```
94
95 At some point in the future, the Future will have been fulfilled, and we can access its value.
96
97 ```C++
98 fut.isReady() == true
99 GetReply& reply = fut.value();
100 ```
101
102 Futures support exceptions. If something exceptional happened, your Future may represent an exception instead of a value. In that case:
103
104 ```C++
105 fut.isReady() == true
106 fut.value() // will rethrow the exception
107 ```
108
109 Just what is exceptional depends on the API. In our example we have chosen not to raise exceptions for `SERVER_ERROR`, but represent this explicitly in the `GetReply` object. On the other hand, an astute Memcache veteran would notice that we left `CLIENT_ERROR` out of `GetReply::Result`, and perhaps a `CLIENT_ERROR` would have been raised as an exception, because `CLIENT_ERROR` means there's a bug in the library and this would be truly exceptional. These decisions are judgement calls by the API designer. The important thing is that exceptional conditions (including and especially spurious exceptions that nobody expects) get captured and can be handled higher up the "stack".
110
111 So far we have described a way to initiate an asynchronous operation via an API that returns a Future, and then sometime later after it is fulfilled, we get its value. This is slightly more useful than a synchronous API, but it's not yet ideal. There are two more very important pieces to the puzzle.
112
113 First, we can aggregate Futures, to define a new Future that completes after some or all of the aggregated Futures complete.  Consider two examples: fetching a batch of requests and waiting for all of them, and fetching a group of requests and waiting for only one of them.
114
115 ```C++
116 vector<Future<GetReply>> futs;
117 for (auto& key : keys) {
118   futs.push_back(mc.get(key));
119 }
120 auto all = whenAll(futs.begin(), futs.end());
121
122 vector<Future<GetReply>> futs;
123 for (auto& key : keys) {
124   futs.push_back(mc.get(key));
125 }
126 auto any = whenAny(futs.begin(), futs.end());
127 ```
128
129 `all` and `any` are Futures (for the exact type and usage see the header files).  They will be complete when all/one of `futs` are complete, respectively. (There is also `whenN()` for when you need *some*.)
130
131 Second, we can attach callbacks to a Future, and chain them together monadically. An example will clarify:
132
133 ```C++
134 Future<GetReply> fut1 = mc.get("foo");
135
136 Future<string> fut2 = fut1.then(
137   [](Try<GetReply>&& t) {
138     if (t.value().result == MemcacheClient::GetReply::Result::FOUND)
139       return t.value().value;
140     throw SomeException("No value");
141   });
142
143 Future<void> fut3 = fut2.then(
144   [](Try<string>&& t) {
145     try {
146       cout << t.value() << endl;
147     } catch (std::exception const& e) {
148       cerr << e.what() << endl;
149     }
150   });
151 ```
152
153 That example is a little contrived but the idea is that you can transform a result from one type to another, potentially in a chain, and unhandled errors propagate. Of course, the intermediate variables are optional. `Try<T>` is the object wrapper that supports both value and exception.
154
155 Using `then` to add callbacks is idiomatic. It brings all the code into one place, which avoids callback hell.
156
157 Up to this point we have skirted around the matter of waiting for Futures. You may never need to wait for a Future, because your code is event-driven and all follow-up action happens in a then-block. But if want to have a batch workflow, where you initiate a batch of asynchronous operations and then wait for them all to finish at a synchronization point, then you will want to wait for a Future.
158
159 Other future frameworks like Finagle and std::future/boost::future, give you the ability to wait directly on a Future, by calling `fut.wait()` (naturally enough). Futures have diverged from this pattern because we don't want to be in the business of dictating how your thread waits. We may work out something that we feel is sufficiently general, in the meantime adapt this spin loop to however your thread should wait:
160
161   while (!f.isReady()) {}
162
163 (Hint: you might want to use an event loop or a semaphore or something. You probably don't want to just spin like this.)
164
165 Futures are partially threadsafe. A Promise or Future can migrate between threads as long as there's a full memory barrier of some sort. `Future::then` and `Promise::setValue` (and all variants that boil down to those two calls) can be called from different threads. BUT, be warned that you might be surprised about which thread your callback executes on. Let's consider an example.
166
167 ```C++
168 // Thread A
169 Promise<void> p;
170 auto f = p.getFuture();
171
172 // Thread B
173 f.then(x).then(y).then(z);
174
175 // Thread A
176 p.setValue();
177 ```
178
179 This is legal and technically threadsafe. However, it is important to realize that you do not know in which thread `x`, `y`, and/or `z` will execute. Maybe they will execute in Thread A when `p.setValue()` is called. Or, maybe they will execute in Thread B when `f.then` is called. Or, maybe `x` will execute in Thread B, but `y` and/or `z` will execute in Thread A. There's a race between `setValue` and `then`—whichever runs last will execute the callback. The only guarantee is that one of them will run the callback.
180
181 Naturally, you will want some control over which thread executes callbacks. We have a few mechanisms to help.
182
183 The first and most useful is `via`, which passes execution through an `Executor`, which usually has the effect of running the callback in a new thread.
184 ```C++
185 aFuture
186   .then(x)
187   .via(e1).then(y1).then(y2)
188   .via(e2).then(z);
189 ```
190 `x` will execute in the current thread. `y1` and `y2` will execute in the thread on the other side of `e1`, and `z` will execute in the thread on the other side of `e2`. `y1` and `y2` will execute on the same thread, whichever thread that is. If `e1` and `e2` execute in different threads than the current thread, then the final callback does not happen in the current thread. If you want to get back to the current thread, you need to get there via an executor.
191
192 This works because `via` returns a deactivated ("cold") Future, which blocks the propagation of callbacks until it is activated. Activation happens either explicitly (`activate`) or implicitly when the Future returned by `via` is destructed. In this example, there is no ambiguity about in which context any of the callbacks happen (including `y2`), because propagation is blocked at the `via` callsites until after everything is wired up (temporaries are destructed after the calls to `then` have completed).
193
194 You can still have a race after `via` if you break it into multiple statements, e.g. in this counterexample:
195 ```C++
196 f = f.via(e1).then(y1).then(y2); // nothing racy here
197 f2.then(y3); // racy
198 ```
199
200 ## You make me Promises, Promises
201
202 If you are wrapping an asynchronous operation, or providing an asynchronous API to users, then you will want to make Promises. Every Future has a corresponding Promise (except Futures that spring into existence already completed, with `makeFuture()`). Promises are simple, you make one, you extract the Future, and you fulfil it with a value or an exception. Example:
203
204 ```C++
205 Promise<int> p;
206 Future<int> f = p.getFuture();
207
208 f.isReady() == false
209
210 p.setValue(42);
211
212 f.isReady() == true
213 f.value() == 42
214 ```
215
216 and an exception example:
217
218 ```C++
219 Promise<int> p;
220 Future<int> f = p.getFuture();
221
222 f.isReady() == false
223
224 p.setException(std::runtime_error("Fail"));
225
226 f.isReady() == true
227 f.value() // throws the exception
228 ```
229
230 It's good practice to use fulfil which takes a function and automatically captures exceptions, e.g.
231
232 ```C++
233 Promise<int> p;
234 p.fulfil([]{
235   try {
236     // do stuff that may throw
237     return 42;
238   } catch (MySpecialException const& e) {
239     // handle it
240     return 7;
241   }
242   // Any exceptions that we didn't catch, will be caught for us
243 });
244 ```
245
246 ## FAQ
247
248 ### Why not use std::future?
249 No callback support.
250 See also http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3428.pdf
251
252 ### Why not use boost::future?
253 - 1.53 is brand new, and not in fbcode
254 - It's still a bit buggy/bleeding-edge
255 - They haven't fleshed out the threading model very well yet, e.g. every single `then` currently spawns a new thread unless you explicitly ask it to work on this thread only, and there is no support for executors yet.
256
257 ### Why use heap-allocated shared state? Why is Promise not a subclass of Future?
258 C++. It boils down to wanting to return a Future by value for performance (move semantics and compiler optimizations), and programmer sanity, and needing a reference to the shared state by both the user (which holds the Future) and the asynchronous operation (which holds the Promise), and allowing either to go out of scope.
259
260 ### What about proper continuations? Futures suck.
261 People mean two things here, they either mean using continuations (as in CSP) or they mean using generators which require continuations. It's important to know those are two distinct questions, but in our context the answer is the same because continuations are a prerequisite for generators.
262
263 C++ doesn't directly support continuations very well. But there are some ways to do them in C/C++ that rely on some rather low-level facilities like `setjmp` and `longjmp` (among others). So yes, they are possible (cf. [Mordor](https://github.com/ccutrer/mordor)).
264
265 The tradeoff is memory. Each continuation has a stack, and that stack is usually fixed-size and has to be big enough to support whatever ordinary computation you might want to do on it. So each living continuation requires a relatively large amount of memory. If you know the number of continuations will be small, this might be a good fit. In particular, it might be faster and the code might read cleaner.
266
267 Futures takes the middle road between callback hell and continuations, one which has been trodden and proved useful in other languages. It doesn't claim to be the best model for all situations. Use your tools wisely.