package main
import (
"fmt"
"sync"
"time"
)
// Completer用于获取未来的结果。仅仅用于接受
type Completer <-chan interface{}
// Future用于构建异步任务。 等这个任务完成之后,所以关心这个结果的任务[其他任务可能在干别的事情]都可以接受到消息。
type Future struct {
triggered bool
item interface{}
err error
lock sync.Mutex
wg sync.WaitGroup
}
// 阻塞等待,知道结果返回
func (f *Future) GetResult()(interface{}, error) {
f.lock.Lock()
if(f.triggered){ // 不需要阻塞就可以获取结果
f.lock.Unlock()
return f.item, f.err
}
f.lock.Unlock()
f.wg.Wait() // 阻塞等待返回结果
return f.item, f.err
}
// 任务是否过期: 是否有结果可以返回
func (f *Future)HasResult() bool {
f.lock.Lock()
hasResult := f.triggered
f.lock.Unlock()
return hasResult
}
func (f *Future) setItem(item interface{}, err error) {
f.lock.Lock()
f.triggered = true // 超时或者已经获取到结果
f.item = item
f.err = err
f.lock.Unlock()
f.wg.Done()
}
func listenForResult(f *Future, ch Completer, timeout time.Duration, wg *sync.WaitGroup) {
wg.Done() // 创建监听器任务已经完成
t := time.NewTimer(timeout)
select {
case item := <-ch:
f.setItem(item, nil)
t.Stop() //我们想在不再需要这个计时器时立即触发它的GC
case <- t.C:
f.setItem(nil, fmt.Errorf(`timeout after %f seconds`, timeout.Seconds()))
}
}
//New是生成future的构造函数。将完成的项目传递到toComplete频道,所有侦听器都将收到通知。
//如果在调用toComplete之前超时,则任何侦听器都将被传递一个错误。
func New(completer Completer, timeout time.Duration) *Future {
f := &Future{}
f.wg.Add(1)
var wg sync.WaitGroup
wg.Add(1)
go listenForResult(f, completer, timeout, &wg)
wg.Wait() // 阻塞等待未来任务完成
return f
}
golang多线程之future
最新推荐文章于 2024-05-31 15:51:14 发布