proxygen
proxygen/folly/folly/docs/Futures.md
Go to the documentation of this file.
1 # Futures
2 
3 ### Futures is a framework for expressing asynchronous code in C++ using the Promise/Future pattern.
4 
5 # Overview
6 
7 Folly Futures is an async C++ framework inspired by [Twitter's Futures](https://twitter.github.io/finagle/guide/Futures.html) implementation in Scala (see also [Future.scala](https://github.com/twitter/util/blob/master/util-core/src/main/scala/com/twitter/util/Future.scala), [Promise.scala](https://github.com/twitter/util/blob/master/util-core/src/main/scala/com/twitter/util/Promise.scala), and friends), and loosely builds 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/doc/html/thread/synchronization.html#thread.synchronization.futures) (especially >= 1.53.0). Although inspired by the C++11 std::future interface, it is not a drop-in replacement because some ideas don't translate well enough to maintain API compatibility.
8 
9 The primary difference from std::future is that you can attach callbacks to Futures (with `thenValue` or `thenTry`), under the control of an executor to manage where work runs, which enables sequential and parallel composition of Futures for cleaner asynchronous code.
10 
11 # Brief Synopsis
12 
13 ```
14 #include <folly/futures/Future.h>
15 #include <folly/executors/ThreadedExecutor.h>
16 using namespace folly;
17 using namespace std;
18 
19 void foo(int x) {
20  // do something with x
21  cout << "foo(" << x << ")" << endl;
22 }
23 
24 // ...
25  folly::ThreadedExecutor executor;
26  cout << "making Promise" << endl;
27  Promise<int> p;
28  Future<int> f = p.getSemiFuture().via(&executor);
29  auto f2 = move(f).thenValue(foo);
30  cout << "Future chain made" << endl;
31 
32 // ... now perhaps in another event callback
33 
34  cout << "fulfilling Promise" << endl;
35  p.setValue(42);
36  move(f2).get();
37  cout << "Promise fulfilled" << endl;
38 ```
39 
40 This would print:
41 
42 ```
43 making Promise
44 Future chain made
45 fulfilling Promise
46 foo(42)
47 Promise fulfilled
48 ```
49 
50 ## Blog Post
51 
52 In addition to this document, there is [a blog post on code.facebook.com (June
53 2015)](https://code.facebook.com/posts/1661982097368498/futures-for-c-11-at-facebook/).
54 
55 # Brief guide
56 This brief guide covers the basics. For a more in-depth coverage skip to the appropriate section.
57 
58 Let's begin with an example using an imaginary simplified Memcache client interface:
59 
60 ```
61 using std::string;
62 class MemcacheClient {
63  public:
64  struct GetReply {
65  enum class Result {
66  FOUND,
67  NOT_FOUND,
68  SERVER_ERROR,
69  };
70 
71  Result result;
72  // The value when result is FOUND,
73  // The error message when result is SERVER_ERROR or CLIENT_ERROR
74  // undefined otherwise
75  string value;
76  };
77 
78  GetReply get(string key);
79 };
80 ```
81 
82 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.
83 
84 Now, consider this traditional asynchronous signature for the same operation:
85 
86 ```
87 int async_get(string key, std::function<void(GetReply)> callback);
88 ```
89 
90 When you call `async_get()`, your asynchronous operation begins and when it finishes your callback will be called with the result. Very performant code can be written with an API like this, but for nontrivial applications the code devolves into a special kind of spaghetti code affectionately referred to as "callback hell".
91 
92 The Future-based API looks like this:
93 
94 ```
95 SemiFuture<GetReply> future_get(string key);
96 ```
97 
98 A `SemiFuture<GetReply>` or `Future<GetReply>` is a placeholder for the `GetReply` that we will eventually get. For most of the descriptive text below, Future can refer to either `folly::SemiFuture` or `folly::Future` as the former is a safe subset of the latter. A Future usually starts life out "unfulfilled", or incomplete, i.e.:
99 
100 ```
101 fut.isReady() == false
102 fut.value() // will throw an exception because the Future is not ready
103 ```
104 
105 At some point in the future, the `Future` will have been fulfilled, and we can access its value.
106 
107 ```
108 fut.isReady() == true
109 GetReply& reply = fut.value();
110 ```
111 
112 Futures support exceptions. If the asynchronous producer fails with an exception, your Future may represent an exception instead of a value. In that case:
113 
114 ```
115 fut.isReady() == true
116 fut.value() // will rethrow the exception
117 ```
118 
119 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".
120 
121 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.
122 
123 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.
124 
125 ```
126 MemcacheClient mc;
127 
128 vector<SemiFuture<GetReply>> futs;
129 for (auto& key : keys) {
130  futs.push_back(mc.future_get(key));
131 }
132 auto all = collectAll(futs.begin(), futs.end());
133 
134 vector<SemiFuture<GetReply>> futs;
135 for (auto& key : keys) {
136  futs.push_back(mc.future_get(key));
137 }
138 auto any = collectAny(futs.begin(), futs.end());
139 ```
140 
141 `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 `collectN()` for when you need some.)
142 
143 Second, we can associate a Future with an executor. An executor specifies where work will run, and we detail this more later. In summary, given an executor we can convert a `SemiFuture` to a `Future` with an executor, or a `Future` on one executor to a `Future` on another executor.
144 
145 For example:
146 
147 ```
148 folly::ThreadedExecutor executor;
149 SemiFuture<GetReply> semiFut = mc.future_get("foo");
150 Future<GetReply> fut1 = std::move(semiFut).via(&executor);
151 ```
152 
153 Once an executor is attached, a `Future` allows continuations to be attached and chained together monadically. An example will clarify:
154 
155 ```
156 SemiFuture<GetReply> semiFut = mc.future_get("foo");
157 Future<GetReply> fut1 = std::move(semiFut).via(&executor);
158 
159 Future<string> fut2 = std::move(fut1).thenValue(
160  [](GetReply reply) {
161  if (reply.result == MemcacheClient::GetReply::Result::FOUND)
162  return reply.value;
163  throw SomeException("No value");
164  });
165 
166 Future<Unit> fut3 = std::move(fut2)
167  .thenValue([](string str) {
168  cout << str << endl;
169  })
170  .thenTry([](folly::Try<string> strTry) {
171  cout << strTry.value() << endl;
172  })
173  .thenError<std::exception>([](std::exception const& e) {
174  cerr << e.what() << endl;
175  });
176 ```
177 
178 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.
179 
180 Using `.thenValue` or `.thenTry` to add callbacks is idiomatic. It brings all the code into one place, which avoids callback hell. `.thenValue` appends a continuation that takes `T&&` for some `Future<T>` and an error bypasses the callback and is passed to the next, `thenTry` takes a callback taking `folly::Try<T>` which encapsulates both value and exception. `thenError<ExceptionType>` will bypass a value and only run if there is an exception, the `ExceptionType` template parameter allows filtering by exception type; `ExceptionType` is optional and if not passed the function will be parameterised with a `folly::exception_wrapper`.
181 
182 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. Futures have a blocking method called `wait()` that does exactly that and optionally takes a timeout.
183 
184 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::thenValue` 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, where we take a future straight from a promise, without going via the safer SemiFuture, and where we therefore have a `Future` that does not carry an executor. This is in general something to avoid.
185 
186 ```
187 // Thread A
188 Promise<Unit> p;
189 auto f = p.getFuture();
190 
191 // Thread B
192 std::move(f).thenValue(x).thenValue(y).thenTry(z);
193 
194 // Thread A
195 p.setValue();
196 ```
197 
198 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.thenValue` is called. Or, maybe `x` will execute in Thread A, but `y` and/or `z` will execute in Thread B. 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.
199 
200 For safety, `.via` should be preferred. We can chain `.via` operations to give very strong control over where callbacks run:
201 
202 ```
203 std::move(aFuture)
204  .thenValue(x)
205  .via(e1).thenValue(y1).thenValue(y2)
206  .via(e2).thenValue(z);
207 ```
208 
209 `x` will execute in the context of the executor associated with `aFuture`. `y1` and `y2` will execute in the context of `e1`, and `z` will execute in the context of `e2`. If after `z` you want to get back to the original context, you need to get there with a call to `via` passing the original executor. Another way to express this is using an overload of `then` that takes an Executor:
210 
211 ```
212 std::move(aFuture)
213  .thenValue(x)
214  .thenValue(e1, y1, y2)
215  .thenValue(e2, z);
216 ```
217 
218 Either way, there is no ambiguity about which executor will run `y1`, `y2`, or `z`.
219 
220 You can still have a race after `via` if you break it into multiple statements, e.g. in this counterexample:
221 
222 ```
223 f2 = std::move(f).via(e1).thenValue(y1).thenValue(y2); // nothing racy here
224 std::move(f2).thenValue(y3); // racy
225 ```
226 
227 # You make me Promises, Promises
228 
229 If you are wrapping an asynchronous operation, or providing an asynchronous API to users, then you will want to make `Promise`s. 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 fulfill it with a value or an exception. Example:
230 
231 ```
232 Promise<int> p;
233 SemiFuture<int> f = p.getSemiFuture();
234 
235 f.isReady() == false
236 
237 p.setValue(42);
238 
239 f.isReady() == true
240 f.value() == 42
241 ```
242 
243 and an exception example:
244 
245 ```
246 Promise<int> p;
247 SemiFuture<int> f = p.getSemiFuture();
248 
249 f.isReady() == false
250 
251 p.setException(std::runtime_error("Fail"));
252 
253 f.isReady() == true
254 f.value() // throws the exception
255 ```
256 
257 It's good practice to use setWith which takes a function and automatically captures exceptions, e.g.
258 
259 ```
260 Promise<int> p;
261 p.setWith([]{
262  try {
263  // do stuff that may throw
264  return 42;
265  } catch (MySpecialException const& e) {
266  // handle it
267  return 7;
268  }
269  // Any exceptions that we didn't catch, will be caught for us
270 });
271 ```