其它语言中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添加回调函数。

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

// Get is used to get future result
func (f *Future) Get() (result interface{}, err error) {
<-f.signal
return f.result, f.err
}
`

NewFuture
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接口。

OnSuccessOnFailureOnCompleteCancel
SetResultSetErrorPromise

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

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

NewPromise()promise.Future.OnSuccess(v interface{}).OnFailure(v interface{}).OnComplete(v interface{}).OnCancel().Get().GetOrTimeout().GetChan().SetTimeout(ms)WhenAll(func1, func2, func3, ...)WhenAny(func1, func2, func3, ...)WhenAnyMatched(func1, func2, func3, ...).Pipe(funcWithDone, funcWithFail).Cancel().IsCancelled()Start(func() (r interface{}, e error))Start(func())Start(func(canceller Canceller) (r interface{}, e error))Start(func(canceller Canceller))Wrap(interface{})Start(taskDone).Done(done1).Fail(fail1).Always(alwaysForDone1).Pipe(f1, f2).Done(done2)

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

参考资料