Many may wonder the etymology of the term “embarrassingly”. In this case, embarrassingly has nothing to do with embarrassment; in fact, it means an overabundance—here referring to parallelization problems which are “embarrassingly easy”.
// 循环执行示例程序,记录各个结果出现次数 funcmain() { var cnt [2]int for i := 0; i < 10000000; i++ { var data int gofunc() { data++ }() if data == 0 { cnt[data]++ } } fmt.Printf("cnt:%v", cnt) } // 执行三次 go run compete.go cnt:[99999770] cnt:[99999920] cnt:[99999800]
funcmain() { cadence := sync.NewCond(&sync.Mutex{}) gofunc() { forrange time.Tick(1 * time.Millisecond) { // 定时发布广播 cadence.Broadcast() } }() takeStep := func() { cadence.L.Lock() cadence.Wait() // 等待唤醒 cadence.L.Unlock() } tryDir := func(dirName string, dir *int32, out *bytes.Buffer)bool { fmt.Fprintf(out, " %v", dirName) atomic.AddInt32(dir, 1) takeStep() if atomic.LoadInt32(dir) == 1 { // 只有一个进程选择该方向 fmt.Fprintf(out, ".success!") } takeStep() atomic.AddInt32(dir, -1) returnfalse } var left, right int32 tryLeft := func(out *bytes.Buffer)bool { return tryDir("left", &left, out) } tryRight := func(out *bytes.Buffer)bool { return tryDir("right", &right, out) } walk := func(walking *sync.WaitGroup, name string) { var out bytes.Buffer defer walking.Done() deferfunc() { // 需放在Done后面保证一定输出 fmt.Println(out.String()) }() fmt.Fprintf(&out, "%v is try to scoot:", name) for i := 0; i < 5; i++ { if tryLeft(&out) || tryRight(&out) { return } } fmt.Fprintf(&out, "\n%v tosses her hands up in exasperation!", name) } var peopleInHallway sync.WaitGroup peopleInHallway.Add(2) go walk(&peopleInHallway, "Alice") go walk(&peopleInHallway, "Bob") peopleInHallway.Wait() }
/* Bob is try to scoot: left right left right left right left right left right Bob tosses her hands up in exasperation! Alice is try to scoot: left right left right left right left right left right Alice tosses her hands up in exasperation! */
funcmain() { var wg sync.WaitGroup var sharedLock sync.Mutex const runtime = 1 * time.Second greedWorker := func() { defer wg.Done() var count int for begin := time.Now(); time.Since(begin) < runtime; { sharedLock.Lock() time.Sleep(3 * time.Nanosecond) sharedLock.Unlock() count++ } fmt.Printf("Greedy worker was able to execute %v work loops\n", count) } politeWorker := func() { defer wg.Done() var count int for begin := time.Now(); time.Since(begin) < runtime; { sharedLock.Lock() time.Sleep(1 * time.Nanosecond) sharedLock.Unlock()
sharedLock.Lock() time.Sleep(1 * time.Nanosecond) sharedLock.Unlock() count++ } fmt.Printf("Polite worker was able to execute %v work loops\n", count) } wg.Add(2) go greedWorker() go politeWorker() wg.Wait() } /* Greedy worker was able to execute 831906 work loops Polite worker was able to execute 564963 work loops */
funcmain() { memConsumed := func()uint64 { runtime.GC() var s runtime.MemStats runtime.ReadMemStats(&s) return s.Sys } var c <-chaninterface{} var wg sync.WaitGroup noop := func() { wg.Done() <-c } const numGoroutines int = 1e5 wg.Add(numGoroutines) before := memConsumed() for i := 0; i < numGoroutines; i++ { go noop() } wg.Wait() after := memConsumed() fmt.Printf("before:%vkb after:%vkb consume:%.3fkb", before/1000, after/1000, float64(after-before)/float64(numGoroutines)/1000) }
funcmain() { c := sync.NewCond(&sync.Mutex{}) queue := make([]interface{}, 0, 10) removeFromQueue := func(delay time.Duration) { time.Sleep(delay) c.L.Lock() queue = queue[:1] fmt.Println("removed from queue") c.L.Unlock() c.Signal() } for i := 0; i < 10; i++ { c.L.Lock() forlen(queue) == 2 { c.Wait() } fmt.Println("add to queue") queue = append(queue, struct{}{}) go removeFromQueue(1 * time.Second) c.L.Unlock() } } /* add to queue add to queue removed from queue add to queue removed from queue add to queue removed from queue add to queue removed from queue add to queue removed from queue add to queue removed from queue add to queue removed from queue add to queue removed from queue add to queue */
funcmain() { var count int increment := func() { count++ fmt.Println("call increment function") }
var once sync.Once var wg sync.WaitGroup wg.Add(100) for i := 0; i < 100; i++ { gofunc() { defer wg.Done() once.Do(increment) }() } wg.Wait() fmt.Printf("count is %d.\n", count) } /* call increment function count is 1. */
另一个示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
funcmain() { var count int increment := func() { count++ } decrement := func() { count-- } var once sync.Once once.Do(increment) once.Do(decrement) fmt.Printf("count is %d\n", count) } /* count is 1 */
sync.Once只计算调用Do方法的次数,而不是多少次唯一调用Do方法。
Pool sync.Pool是Pool模式的并发安全实现,在较高的层次上,Pool模式是一种创建和提供可供使用的固定数量实例或Pool实例的方法。它通常用于创建昂贵的场景(数据库连接),以便只创建固定数量的实例,但不确定数量的操作仍然可用请求访问这些场景(什么鬼翻译)。对于Go语言的sync.Pool,这种数据类型可以被多个goroutine安全地使用
funcmain() { begin := make(chaninterface{}) var wg sync.WaitGroup wg.Add(5) for i := 0; i < 5; i++ { gofunc(i int) { defer wg.Done() <-begin // 在channel上等待 fmt.Printf("%d has begun\n", i) }(i) } fmt.Println("Unblocking goroutines...") close(begin) // 关闭channel wg.Wait() } /* Unblocking goroutines... 0 has begun 2 has begun 4 has begun 3 has begun 1 has begun */
funcmain() { var stdoutBuffer bytes.Buffer defer stdoutBuffer.WriteTo(os.Stdout) // 最后输出结果
inStream := make(chanint, 4) gofunc() { deferclose(inStream) // 写入完成后关闭channel defer fmt.Fprintln(&stdoutBuffer, "Producer Done.") for i := 0; i < 5; i++ { fmt.Fprintf(&stdoutBuffer, "Send:%d\n", i) inStream <- i } }()
for integer := range inStream { // 循环读取channel中的值,并在channel关闭后自动中断循环 fmt.Fprintf(&stdoutBuffer, "Received %d\n", integer) } } /* Send:0 Send:1 Send:2 Send:3 Send:4 Producer Done. Received 0 Received 1 Received 2 Received 3 Received 4 */
var c1Count, c2Count int for i := 10000; i > 0; i-- { select { case <-c1: c1Count++ case <-c2: c2Count++ } } fmt.Printf("c1:%d c2:%d\n", c1Count, c2Count) } // c1:5029 c2:4971