转载

使用Golang实现Futures 和 Promises

其它语言中Future和Promise的概念大量存在, 比如Node.js、Scala、Java、C#、C++ 11、Scheme、Swift等,可以方便的实现异步执行和回调。但是在Go语言的世界里,我们是通过goroutine/channel实现这种类似的功能呢,goroutine之间可以通过channel进行通讯, 但是,如果我们还是想使用Future/Promise的功能的话,该如何实现呢?

Future,Promise或Delay是用于并发编程的一种设计模式。它们表示一个对象,这个对象用来作为一次计算结果的代理,而该结果开始的时候是未知的,因为计算还没有完成。Promise与Future的区别在于,Future是Promise的一个只读的视图,也就是说Future没有设置任务结果的方法,只能获取任务执行结果或者为Future添加回调函数。

下面演示了实现一个Go Future的实现。因为Go目前还没有泛型的概念,所以为了使代码更通用,我会使用 interface{} 代表一个通用的对象。

首先定义一个 Future 结构,

go type Future struct { result interface{} //计算结果 err error //错误 signal chan struct{} //等待完成的信号 IsCompleted bool //计算是否完成 }

这个Future可以执行下面的计算 func() (interface{}, error) ,所以计算方法应该实现为 FutureFunc 类型的函数,它会返回结果或者返回error:

go type FutureFunc func() (interface{}, error)

然后定义获取结果的 GetGetOrTimeout 方法,它会阻塞直到获得结果或者超时(GetOrTimeout)。

`go

// GetOrTimeout is similar to Get(), but GetOrTimeout will not block after timeout.

func (f *Future) GetOrTimeout(d time.Duration) (result interface{}, err error, timeout bool) {

select {

case <-time.After(d):

return nil, nil, true

case <-f.signal:

return f.result, f.err, false

}

}

// Get is used to get future result

func (f *Future) Get() (result interface{}, err error) {

<-f.signal

return f.result, f.err

}

`

然后定义 NewFuture 就可以了:

`go

func NewFuture(fun FutureFunc) *Future {

f := new(Future)

f.signal = make(chan struct{}, 1)  go func() {     defer close(f.signal)     result, err := fun()     f.result = result     f.err = err     f.IsCompleted = true }()  return f 

}`

一个使用的例子:

`go

func ExampleRequestFuture() {

requestFunc := func() (body interface{}, err error) {

url := " http://www.baidu.com "

var resp *http.Response

resp, err = http.Get(url)

if err != nil {

return

}

defer resp.Body.Close()

bodyBytes, err := ioutil.ReadAll(resp.Body)

return string(bodyBytes), err

}

requestFuture := NewFuture(FutureFunc(requestFunc)) body, err, timeout := requestFuture.GetOrTimeout(10 * time.Second) if timeout {     fmt.Println("timeout") } else {     if err != nil {         fmt.Printf("error: %v/n", err)     } else {         fmt.Printf("body: %v/n", body)     } } 

}`

如果你是一个Java程序了,可以发现这个Future类似Java中的 Future接口 。

当然这个Future实现的还是非常的简陋,至少还应该实现回调接口比如 OnSuccessOnFailureOnComplete 等方法,另外一些方法如 Cancel 也应该加上。

为了组合多个Future,避免掉入"回调陷阱",还应该实现Future的组合方法。

为了实现 SetResultSetError 的功能,可以实现一个类似的 Promise 的功能。

但是,目前我不会去实现这个功能,一是目前我没有这方面的需求,而是 @fanliao 已经实现了这样的一个框架,名字叫 go-promise ,代码放在了github上,我们不必再重复造轮子了。

这个框架提供了丰富的功能:

  • Future and Promise

    • NewPromise()
    • promise.Future
  • Promise and Future callbacks

    • .OnSuccess(v interface{})
    • .OnFailure(v interface{})
    • .OnComplete(v interface{})
    • .OnCancel()
  • Get the result of future

    • .Get()
    • .GetOrTimeout()
    • .GetChan()
  • Set timeout for future

    • .SetTimeout(ms)
  • Merge multiple promises

    • WhenAll(func1, func2, func3, ...)
    • WhenAny(func1, func2, func3, ...)
    • WhenAnyMatched(func1, func2, func3, ...)
  • Pipe

    • .Pipe(funcWithDone, funcWithFail)
  • Cancel the future

    • .Cancel()
    • .IsCancelled()
  • Create future by function

    • Start(func() (r interface{}, e error))
    • Start(func())
    • Start(func(canceller Canceller) (r interface{}, e error))
    • Start(func(canceller Canceller))
  • Immediate wrappers

    • Wrap(interface{})
  • Chain API

    • Start(taskDone).Done(done1).Fail(fail1).Always(alwaysForDone1).Pipe(f1, f2).Done(done2)

使用例子可以看他的项目文档。

参考资料

  1. https://en.wikipedia.org/wiki/Futures_and_promises
  2. http://labs.strava.com/blog/futures-in-golang/
  3. https://github.com/fanliao/go-promise
原文  http://colobu.com/2016/04/14/Futures-and-Promises-in-golang/
正文到此结束
Loading...