Tour of Go 03 :Goroutines Channels(中英互译)

88 阅读3分钟

Channels

管道的创建和使用

Channels are a typed conduit through which you can send and receive values with the channel operator, <-. 通道是一种类型化的管道,您可以通过它使用通道运算符 <- 发送和接收值。

ch <- v    // Send v to channel ch.发送
v := <-ch  // Receive from ch, and接收
           // assign value to v给v分配值

Channels buffered

Channels can be buffered. Provide the buffer length as the second argument to make to initialize a buffered channel: 通道可以有缓冲区。缓冲区是一种存储数据的空间,可以让你一次发送多个数据值。创建通道时,可以用 make 函数的第二个参数指定缓冲区的长度,例如 ch := make (chan int, 100) 就创建了一个可以存储 100 个 int类型的数据的缓冲通道12。

Range and Close 范围和关闭

A sender can close a channel to indicate that no more values will be sent. Receivers can test whether a channel has been closed by assigning a second parameter to the receive expression: after 发送者可以 close 一个通道来表示不再发送任何值。接收者可以通过为接收表达式分配第二个参数来测试通道是否已关闭:之后

v, ok := <-ch

The loop for i := range c receives values from the channel repeatedly until it is closed. 循环 for i := range c 重复从通道接收值,直到它关闭。

Note: Only the sender should close a channel, never the receiver. Sending on a closed channel will cause a panic.

Select

The select statement lets a goroutine wait on multiple communication operations. select 语句让 goroutine 等待多个通信操作。

A select blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready. select 阻塞直到它的一个 case 可以运行,然后它执行那个 case。如果多个准备就绪,它会随机选择一个。

package main

import (
	"fmt"
	"time"
)

func main() {
	// fmt.Println("my way to go")
	c1 := make(chan string, 1)
	c2 := make(chan string, 1)
	c3 := make(chan string, 1)
	go func() {
		time.Sleep(1 * time.Second)
		c1 <- "one"
	}()
	go func() {
		time.Sleep(2 * time.Second)
		c2 <- "two"
	}()
	go func() {
		time.Sleep(1 * time.Second)
		c3 <- "three"
	}()
	for i := 0; i < 3; i++ {
		select {
		case msg1 := <-c1:
			fmt.Println("received", msg1)
		case msg2 := <-c2:
			fmt.Println("received", msg2)
		case msg3 := <-c3:
			fmt.Println("received", msg3)
		}
	}
}

Note that the total execution time is only ~2 seconds since both the 1 and 2 second Sleeps execute concurrently. 请注意,总执行时间仅为 ~2 秒,因为 1 秒和 2 秒 Sleeps 同时执行。

超时

  • Here’s the select implementing a timeout. res := <-c1 awaits the result and <-time.After awaits a value to be sent after the timeout of 1s. Since select proceeds with the first receive that’s ready, we’ll take the timeout case if the operation takes more than the allowed 1s. 这是实现超时的 select 。 res := <-c1 等待结果, <-time.After 等待 1 秒超时后发送的值。由于 select 继续第一个准备好的接收,如果操作花费的时间超过允许的 1,我们将采用超时情况。
    c1 := make(chan string, 1)
	//c2 := make(chan string, 1)
	go func() {
		//延时2s
		time.Sleep(2 * time.Second)
		c1 <- "one"
	}()
	select {
	case res := <-c1:
		fmt.Println(res)
	case <-time.After(2 * time.Second):
		fmt.Println("timeout 1")
	}

Non-Blocking Channel Operations非阻塞通道操作

Basic sends and receives on channels are blocking. However, we can use select with a default clause to implement non-blocking sends, receives, and even non-blocking multi-way selects. 通道上的基本发送和接收是阻塞的。但是,我们可以使用带有 default 子句的 select 来实现非阻塞发送、接收,甚至是非阻塞多路 select 。 A non-blocking send works similarly. Here msg cannot be sent to the messages channel, because the channel has no buffer and there is no receiver. Therefore the default case is selected. 非阻塞发送的工作方式类似。这里 msg 不能发送到 messages 通道,因为通道没有buffer,也没有receiver。因此选择了 default 案例。

    messages := make(chan string)
    msg := "hi"
    select {
    case messages <- msg:
        fmt.Println("sent message", msg)
    default:
        fmt.Println("no message sent")
    }

We can use multiple cases above the default clause to implement a multi-way non-blocking select. Here we attempt non-blocking receives on both messages and signals. 我们可以在 default 子句之上使用多个 case 来实现多路非阻塞select。在这里,我们尝试在 messages 和 signals 上进行非阻塞接收。

	message := make(chan string)
	signal := make(chan string, 1)
	select {
	case msg := <-message:
		fmt.Println("received message", msg)
	case sig := <-signal:
		fmt.Println("received signal", sig)
	default:
		fmt.Println("no activity")
	}