只运行一次代码块
的情况下,当多个goroutines运行相同的代码,有代码块初始化,例如,共享的资源,走标准库提供的解决方案,这将进一步描述。
package main
import (
"fmt"
"sync"
"time"
)
var names = []interface{}{"Alan", "Joe", "Jack", "Ben",
"Ellen", "Lisa", "Carl", "Steve", "Anton", "Yo"}
type Source struct {
m *sync.Mutex
o *sync.Once
data []interface{}
}
func (s *Source) Pop() (interface{}, error) {
s.m.Lock()
defer s.m.Unlock()
s.o.Do(func() {
time.Sleep(time.Second * 3)
s.data = names
fmt.Println("Data has been loaded.")
})
if len(s.data) > 0 {
res := s.data[0]
s.data = s.data[1:]
return res, nil
}
return nil, fmt.Errorf("No data available")
}
func main() {
s := &Source{&sync.Mutex{}, &sync.Once{}, nil}
wg := sync.WaitGroup{}
wg.Add(10)
for i := 0; i < 10; i++ {
go func(idx int) {
// This code block is done only once
if val, err := s.Pop(); err == nil {
fmt.Printf("Pop %d returned: %s
", idx, val)
}
wg.Done()
}(i)
}
wg.Wait()
}
/*
Data has been loaded.
Pop 1 returned: Alan
Pop 3 returned: Ben
Pop 9 returned: Joe
Pop 2 returned: Jack
Pop 4 returned: Ellen
Pop 6 returned: Carl
Pop 7 returned: Steve
Pop 8 returned: Anton
Pop 0 returned: Yo
Pop 5 returned: Lisa
*/
示例代码演示了在访问容器结构时对数据的延迟加载。由于数据应该只加载一次,所以在方法弹出中使用了同步包中的一次结构。前者只执行一个名为do的方法,该函数不需要参数就使用函数,在执行过程中每次执行一次函数只执行一次。
DO方法调用块直到第一次运行完成。这一事实与一次被用于初始化的事实相对应。