BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース 堅牢で強力なFeatureをC++11で実現するFacebook Folly Feature

堅牢で強力なFeatureをC++11で実現するFacebook Folly Feature

ブックマーク

原文(投稿日:2015/07/13)へのリンク

Facebookは先頃,Folly Futureという,既存のstd::futureを機能拡張するC++11ライブラリを導入した

Futureは並列操作の同期に使用される構成要素である。最初は値の分からない非同期演算の結果を参照する,読み取り専用のプロキシオブジェクトがFutureだ。まだ完了(fulfill)していないFutureの値をクライアントが読み出そうとすると,そのクライアントはブロックされる。ひとつのFutureは通常,ひとつのPromiseに関連付けられている。Futureの値への書き込みアクセスを提供するのがPromiseだ。

以下のコードで示すような非同期操作では,ブロックされることなく,読み取り専用のFutureをすぐに返すことが可能だ。

#include <folly/futures/Future.h> 
using folly::Future;

Future<Output> asyncOperation(Input);
Future<Output> f = asyncOperation(input);

asyncOperationは非同期呼び出しのラッパである。 クライアントは次にFutureにアクセスして,関連するPromiseisReady()メソッドを使って完了しているかチェックした上で,value()を使ってその値を取得する。

Futureはその関連するPromiseから生成されて,setValue()setWith()のいずれかを使って値を設定することができる。

using folly::Promise;

Future<double> getEnergy(int year) {
  auto promise = make_shared<Promise<double>>();

  std::thread([=]{
    promise->setWith(std::bind(getEnergySync, year));
  }).detach();
  
  return promise->getFuture();
}

Folly Futuresが本領を発揮するのはFuture::thenメソッドを使うときだ。コールバックの連鎖が簡単に実現可能であるため,コールバック地獄を防止できる。チェーンがどのように動作するのかを以下に示す。

Future<OutputA> futureA(Output);
Future<OutputB> futureB(OutputA);
Future<OutputC> futureC(OutputB);

OutputD d(OutputC) {
  if (somethingExceptional) throw anException;
  return OutputD();
}

Future<double> fut =
  fooFuture(input)
  .then(futureA)
  .then(futureB)
  .then(futureC)
  .then(d)
  .then([](OutputD outputD) { // lambdas are ok too
    return outputD * M_PI;
  });

Folly Futuresの提供する,もうひとつの強力なビルディングブロックがcollectメソッドだ。Futureのコレクションを,すべてのFutureの完了によって完了状態になる単一のFutureとして扱うことができる。collertと同じように,次の機能も提供されている。

  • collectAny: 入力のFutureのいずれかの完了によって完了する。
  • collectN: N個のFutureが完了するまで待機する。
  • map: Futureのコレクションと関数を設定し,各入力Futureのthen()に対してその関数をコールする。Futureの別の配列を返す。
  • reduce: Futureのコレクション以外に2つの引数関数(換算値と換算シーケンスの次の値)を取って,それぞれのFutureにその関数を適用する。

最後に,Folly Futuresでは,コールバックの実行時に実行コンテキストの概念もサポートされている。executorオブジェクトをthenに渡して,そのコールバックをexecutor経由で行うようなことも可能だ。

struct Executor {
  using Func = std::function<void()>;
  virtual void add(Func) = 0;
};

a(input).then(executor, b);

Folly Futureの詳しい情報は,資料で見ることができる。

この記事に星をつける

おすすめ度
スタイル

BT