2016-03-10 9 views
5

私はJavascriptと同様のPromiseを実装しようとしています。Goでチャネルを使用してPromiseを実装する

  1. は右 すぐメインゴルーチンにPromiseを返すゴルーチンを実行します。

    type Promise struct { 
         Result chan string 
         Error chan error 
    } 
    
    func NewPromise() (*Promise) { 
         r := make(chan string, 1) 
         e := make(chan error, 1) 
         return &Promise{ 
           Result: r, 
           Error: e, 
         } 
    } 
    
    func main() { 
         var p = NewPromise() 
    
         go func(p *Promise) { 
           time.Sleep(time.Duration(5)*time.Second) 
           p.Result <- "done" 
         }(p) 
    
         if <- p.Result { 
           fmt.Println(<-p.Result) 
         } 
    
         // Is it possible to do something else here while wait for 5s? 
    
         // Once Promise is fulfilled after 5s, the Result is available. 
    } 
    

    は、どのように私は次の操作を行います。何かが送信されると、ゴルーチンから復帰して読み取ることがその チャネルを利用できるようPromise.ResultまたはPromise.Error

  2. のいずれかに送信する 何を待っている間

  3. 非同期にメインルーチンに何かをします。

答えて

7

それが少し速く/より効率的にチャンネルを使用せずに別のアプローチ、:

type Promise struct { 
    wg sync.WaitGroup 
    res string 
    err error 
} 

func NewPromise(f func() (string, error)) *Promise { 
    p := &Promise{} 
    p.wg.Add(1) 
    go func() { 
     p.res, p.err = f() 
     p.wg.Done() 
    }() 
    return p 
} 

func (p *Promise) Then(r func(string), e func(error)) { 
    go func() { 
     p.wg.Wait() 
     if p.err != nil { 
      e(p.err) 
      return 
     } 
     r(p.res) 
    }() 
} 

playground

1

あり、これを行うための方法のトンがありますが、私は例えばやったことは、結果やエラーチャンネルを受け入れる引数としての機能を取るためにNewPromiseを()調整されています。次に、NewPromiseメソッドは、この関数を使ってgoルーチンを初期化し、読み込むべき同じチャネルで約束を返します。 .Thenメソッドを呼び出すと、これは基本的に引数として2つの関数を取ります。結果チャネル(文字列)を通過する型とエラーチャネルの結果型を処理する型(エラー)を処理するもの。その後、.Thenメソッドはゴルーチンのプライベート.then()メソッドを呼び出して、結果またはエラーのいずれかが最初に発生するかどうかを選択し、各結果に適した関数を呼び出します。

この例では、1秒間待ってから結果チャンネルを介して「hi」を送信する単純なティッカーしか使用していません。

これは、これを行う1つの方法のアイデアを提供したいと思います。

GoLang遊び場: https://play.golang.org/p/xc1xvv7hRx

2

Martin Sulzmannによって"From Events to Futures and Promises and back"と呼ばれる紙があります(2016年2月に出版されています)。要約は

に基づいています。チャネル通信と未来/約束に基づくイベントは、並行プログラミングにとっては強力ですが外見上は異なる概念です。驚くほど小さな労力で、一方の概念を他方の概念で表すことができることを示します。私たちの結果は、イベントや未来/約束を実装するための軽量ライブラリベースのアプローチを提供しています。経験的な結果は、我々のアプローチが実際にうまくいくことを示している。

紙によると、先物は次のようになります。次のような約束が実現されているのに対し

type Comp struct { 
    value interface{} 
    ok bool 
} 

type Future chan Comp 

func future(f func() (interface{}, bool)) Future { 
    future := make(chan Comp) 

    go func() { 
     v, o := f() 
     c := Comp{v, o} 
     for { 
      future <- c 
     } 
    }() 

    return future 
} 

type Promise struct { 
    lock chan int 
    ft Future 
    full bool 
} 

func promise() Promise { 
    return Promise{make(chan int, 1), make(chan Comp), false} 
} 

func (pr Promise) future() Future { 
    return pr.ft 
} 

詳細、コンビネータおよび多くのための論文を読んでください。

関連する問題