2

Address オブジェクトをジオコーディングし、更新された Address を検索エンジンに格納する必要があります。これは、オブジェクトを取得し、オブジェクトに対して長時間実行される操作を 1 回実行してから、オブジェクトを永続化するという単純化できます。これは、永続化が発生する前に最初の操作が完了するという操作の順序要件があることを意味します。

Akka を使用して、これを実行のメイン スレッドから外したいと思います。

私の最初の考えは、Future のペアを使用してこれを達成することでしたが、Future のドキュメントでは、どの動作 (フォールド、マップなど) が 1 つの Future が別の Future の前に実行されることを保証するかについて完全に明確ではありません。

まず、それぞれの操作に対して Future を返す2 つの関数を作成しましたdefferedGeocodedeferredWriteToSearchEngineを使用してそれらを連鎖させますFuture<>.andThen(new OnComplete...)が、これはすぐにぎこちなくなります。

Future<Address> geocodeFuture = defferedGeocode(ec, address);

geocodeFuture.andThen(new OnComplete<Address>() {
    public void onComplete(Throwable failure, Address geocodedAddress) {
        if (geocodedAddress != null) {
            Future<Address> searchEngineFuture = deferredWriteToSearchEngine(ec, addressSearchService, geocodedAddress);

            searchEngineFuture.andThen(new OnComplete<Address>() {
                public void onComplete(Throwable failure, Address savedAddress) {
                    // process search engine results
                }
            });
        }
    }
}, ec);

そして、次deferredGeocodeのように実装されます。

private Future<Address> defferedGeocode(
        final ExecutionContext ec, 
        final Address address) {

    return Futures.future(new Callable<Address>() {
        public Address call() throws Exception {
            log.debug("Geocoding Address...");
            return address;
        }
    }, ec);

};

deferredWriteToSearchEngineは とよく似てdeferredGeocodeいますが、追加の最終パラメーターとして検索エンジン サービスを使用する点が異なります。

私の理解では、先物は計算を実行するために使用されるものであり、副作用があってはならないということです。この場合、住所のジオコーディングは計算なので、Future を使用することは合理的だと思いますが、検索エンジンへの書き込みは間違いなく副作用です。

Akka のベスト プラクティスは何ですか? ネストされた呼び出しをすべて回避するにはどうすればよいですか?ただし、ジオコーディングと検索エンジンの書き込みの両方がメイン スレッドから離れて実行されるようにするにはどうすればよいですか?

より適切なツールはありますか?

アップデート:

以下のViktorのコメントに基づいて、私は今このコードを試しています:

ExecutionContext ec;
private Future<Address> addressBackgroundProcess(Address address) {
    Future<Address> geocodeFuture = addressGeocodeFutureFactory.defferedGeocode(address);

    return geocodeFuture.flatMap(new Mapper<Address, Future<Address>>() {
        @Override
        public Future<Address> apply(Address geoAddress) {
            return addressSearchEngineFutureFactory.deferredWriteToSearchEngine(geoAddress);
        }
    }, ec);
}

私が興奮していない1つの問題を除いて、これはうまくいくようです。私たちは Spring IOC コード ベースで作業しているので、ExecutionContext を FutureFactory オブジェクトに挿入したいと考えていますが、(DAO 内の) この関数が ExecutionContext を認識する必要があるのは間違っているようです。

両方の先物が EC を提供するため、flatMap() 関数が EC をまったく必要とするのは奇妙に思えます。

関心の分離を維持する方法はありますか? コードの構造が悪いのでしょうか、それともこれでいいのでしょうか?

FutureFactory の連鎖を可能にするインターフェイスを FutureFactory 内に作成することを考えたので、flatMap() 呼び出しは FutureFactory 基本クラスにカプセル化されますが、これは意図的な Akka の設計上の決定を故意に覆すようです。

4

1 に答える 1

1

警告: 疑似コードが先です。

Future<Address> myFutureResult = deferredGeocode(ec, address).flatMap(
  new Mapper<Address, Future<Address>>() {
    public Future<Address> apply(Address geocodedAddress) {
      return deferredWriteToSearchEngine(ec, addressSearchService, geocodedAddress);
   }
  }, ec).map(
     new Mapper<Address, SomeResult>() {
       public SomeResult apply(Address savedAddress) {
         // Create SomeResult after deferredWriteToSearchEngine is done
       }
    }, ec);

ネストされていないことを確認してください。flatMap と map は、操作の順序付けに使用されます。"andThen" は、結果を渡す前に、副作用のみの操作を完全に完了させたい場合に便利です。もちろん、同じ future-instance に 2 回マッピングした場合、順序は保証されませんが、flatMapping と返された先物 (ドキュメントによると新しいもの) のマッピングであるため、プログラムには明確なデータフローがあります。 .

于 2013-11-04T19:58:29.093 に答える