2016-03-10 70 views
5

我試圖在Go中實現Promise,它與Javascript中的類似。在Go中實現承諾

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. 
} 

如何做到以下幾點:

  1. 運行的goroutine,它會返回Promise到主夠程權 了。
  2. 異步做主程序的東西,而等待 什麼將其發送到Promise.ResultPromise.Error

  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方法用這個函數初始化一個去程序,並返回帶有相同通道的承諾讀取。如果你調用.Then方法,這基本上以兩個函數作爲參數。一個將處理您通過結果通道傳遞的類型(字符串),另一個處理錯誤通道的結果類型(錯誤)。 .Then方法然後在goroutine中調用一個私有的.then()方法,以選擇首先發生的結果或錯誤,然後調用適合於每個結果的函數。

對於這個例子,我只用了一個簡單的ticker,等待一秒鐘,然後通過結果通道發送「hi」。

我希望這給你一個辦法做到這一點的想法。

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 
} 

閱讀了有關詳細信息,組合子多的紙。