简体   繁体   中英

Why can you reuse channels in Go when doing parallel processing?

Here is a code snippet from the official tutorial

package main

import "fmt"

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c <- sum // send sum to c
}

func main() {
    s := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)
    x, y := <-c, <-c // receive from c

    fmt.Println(x, y, x+y)
}

Since we are doing the calculation in parallel, and each thread saves its result into the same channel, doesn't this screw up the data?

It's true that when you send two values over a channel from two different goroutines that the ordering is not necessarily guaranteed (unless you've done something else to coordinate their sends).

However, in this example, the ordering doesn't matter at all. Two values are being sent on the channel: the sum of the first half and the sum of the second.

go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)

Since the only thing those two values are used for is to calculate the total sum, the order doesn't matter at all. In fact, if you ran the example enough times you should see that x and y are often swapped, but the sum x+y is always the same.

Operations with channels are goroutine safe. You can read/write/close in any goroutine without corrupting anything that goes in or out of the channel. Basically, channels are synchronization points. Unbuffered channels (like in your case) will block on every write and read. When you write your code will block and wait until someone starts reading on the other end. When you read your code will block and wait until someone starts writing on the other end.

In your case calculations in goroutines will be done concurrently (not necessary in parallel) but will block on channel write. Your main goroutine will block on the first read, read the value. Block on the second read, read the value.

Even if you use a buffered channel - c := make(chan int, 2) . Your goroutines will finish calculations, write resuls to the channel without blocking and terminate. Nothing will be corrupted. In the meantime main goroutine will block on channel read and wait until someone writes to it.

I suggest you read effective go , Go Concurrency Patterns and try A Tour of Go

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM