Go-并发编程-goroutine 和 channel(二)

2023-04-21 13:40:27 浏览数 (1)

Channel

Channel是一种用于在Goroutine之间传递数据的通信机制。Channel可以看作是Goroutine之间的管道,一个Goroutine可以向通道中发送数据,而另一个Goroutine则可以从通道中接收数据。Channel既支持同步通信,也支持异步通信。

在Go中,使用make函数创建一个通道,例如:

代码语言:javascript复制
c := make(chan int)

在上面的示例中,我们创建了一个整型通道c。使用通道时,需要注意以下几点:

  • 发送数据时,可以使用<-运算符,例如:c <- 1。
  • 接收数据时,也可以使用<-运算符,例如:x := <- c。
  • 通道默认是阻塞的,即发送方会一直等待接收方接收数据。因此,在接收数据之前,必须有一个Goroutine在通道中等待接收数据。
  • 通道可以设置缓冲区大小,例如:c := make(chan int, 10)。如果缓冲区已满,发送方会被阻塞,直到有接收方从通道中读取数据。

以下是一个使用通道进行异步通信的示例:

代码语言:javascript复制
func compute(a int, b int, c chan int) {
    c <- a   b
}

func main() {
    c := make(chan int)
    go compute(1, 2, c)
    fmt.Println("Waiting for result...")
    result := <-c
    fmt.Println("Result:", result)
}

在上面的示例中,我们创建了一个整型通道c,并使用go关键字启动了一个compute函数的Goroutine。在主函数中,我们打印“Waiting for result...”表示正在等待计算结果。然后,我们从通道c中接收计算结果,并将其打印出来。

由于通道是阻塞的,因此在compute函数中向通道发送数据时,程序会被阻塞,直到有接收方从通道中读取数据。在主函数中,我们先打印了“Waiting for result...”,然后才从通道中读取数据,因此主函数会一直等待计算结果。

以下是一个使用通道进行同步通信的示例:

代码语言:javascript复制
func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        fmt.Println("Worker", id, "processing job", j)
        time.Sleep(time.Second)
        results <- j * 2
    }
}

func main() {
    numJobs := 5
    jobs := make(chan int, numJobs)
    results := make(chan int, numJobs)

    for w := 1; w <= 3; w   {
        go worker(w, jobs, results)
    }

    for j := 1; j <= numJobs; j   {
        jobs <- j
    }
    close(jobs)

    for a := 1; a <= numJobs; a   {
        <-results
    }
}

在上面的示例中,我们定义了一个worker函数,它接受一个ID、一个任务通道和一个结果通道作为参数。在worker函数中,我们从任务通道中读取任务,并处理该任务,然后将处理结果发送到结果通道中。

在主函数中,我们创建了两个通道:一个任务通道jobs和一个结果通道results。我们使用for循环启动了三个worker函数的Goroutine,并将任务通道和结果通道作为参数传递给它们。然后,我们向任务通道中发送5个任务,然后关闭任务通道。最后,我们从结果通道中读取5个结果。

由于任务通道和结果通道都是阻塞的,因此worker函数会一直等待任务和发送结果,直到有任务和接收方。在主函数中,我们先向任务通道中发送了5个任务,然后从结果通道中读取了5个结果。由于worker函数和主函数是并发运行的,因此它们可以同时处理任务和发送/接收结果。

go

0 人点赞