go实例之轻量级线程goroutine、通道channel与select
1、goroutine线程
goroutine
是一个轻量级的执行线程。假设有一个函数调用f(s)
,要在goroutine
中调用此函数,请使用go f(s)
。 这个新的goroutine
将与调用同时执行。
示例代码如下:
1 package main 2 3 import "fmt" 4 5 func f(from string) { 6 for i := 0; i < 3; i++ { 7 fmt.Println(from, ":", i) 8 } 9 } 10 11 func main() { 12 13 // Suppose we have a function call `f(s)`. Here's how 14 // we'd call that in the usual way, running it 15 // synchronously. 16 f("direct") 17 18 // To invoke this function in a goroutine, use 19 // `go f(s)`. This new goroutine will execute 20 // concurrently with the calling one. 21 go f("goroutine") 22 23 // You can also start a goroutine for an anonymous 24 // function call. 25 go func(msg string) { 26 fmt.Println(msg) 27 }("going") 28 29 // Our two function calls are running asynchronously in 30 // separate goroutines now, so execution falls through 31 // to here. This `Scanln` code requires we press a key 32 // before the program exits. 33 var input string 34 fmt.Scanln(&input) 35 fmt.Println("done") 36 }
执行上面代码,将得到以下输出结果
1 direct : 0 2 direct : 1 3 direct : 2 4 goroutine : 0 5 goroutine : 1 6 goroutine : 2 7 going
2、通道
通道是连接并发goroutine
的管道。可以从一个goroutine
向通道发送值,并在另一个goroutine
中接收到这些值。
1 package main 2 3 import "fmt" 4 5 func main() { 6 7 // Create a new channel with `make(chan val-type)`. 8 // Channels are typed by the values they convey. 9 messages := make(chan string) 10 11 // _Send_ a value into a channel using the `channel <-` 12 // syntax. Here we send `"ping"` to the `messages` 13 // channel we made above, from a new goroutine. 14 go func() { messages <- "ping" }()//使用"<-"向通道发送消息 15 16 // The `<-channel` syntax _receives_ a value from the 17 // channel. Here we'll receive the `"ping"` message 18 // we sent above and print it out. 19 msg := <-messages//"从通道读取数据" 20 fmt.Println(msg) 21 }
默认情况下,通道是未缓冲的,意味着如果有相应的接收(<- chan
)准备好接收发送的值,它们将只接受发送(chan <-
)。使用make的第二个参数指定缓冲大小
1 package main 2 3 import "fmt" 4 5 func main() { 6 7 // Here we `make` a channel of strings buffering up to 8 // 2 values. 9 messages := make(chan string, 2) 10 11 // Because this channel is buffered, we can send these 12 // values into the channel without a corresponding 13 // concurrent receive. 14 messages <- "buffered" 15 messages <- "channel" 16 17 // Later we can receive these two values as usual. 18 fmt.Println(<-messages) 19 fmt.Println(<-messages) 20 }
3、通道同步
1 package main 2 3 import "fmt" 4 import "time" 5 6 // This is the function we'll run in a goroutine. The 7 // `done` channel will be used to notify another 8 // goroutine that this function's work is done. 9 func worker(done chan bool) { 10 fmt.Print("working...") 11 time.Sleep(time.Second) 12 fmt.Println("done") 13 14 // Send a value to notify that we're done. 15 done <- true 16 } 17 18 func main() { 19 20 // Start a worker goroutine, giving it the channel to 21 // notify on. 22 done := make(chan bool, 1) 23 go worker(done) 24 25 // Block until we receive a notification from the 26 // worker on the channel. 27 <-done 28 }
当使用通道作为函数参数时,可以指定通道是否仅用于发送或接收值。这种特殊性增加了程序的类型安全性。chan<-
表示发送,<-chan
表示接收
4、select
每个通道将在一段时间后开始接收值,以模拟阻塞在并发goroutines
中执行的RPC
操作。我们将使用select
同时等待这两个值,在每个值到达时打印它们。
1 package main 2 3 import "time" 4 import "fmt" 5 6 func main() { 7 8 // For our example we'll select across two channels. 9 c1 := make(chan string) 10 c2 := make(chan string) 11 12 // Each channel will receive a value after some amount 13 // of time, to simulate e.g. blocking RPC operations 14 // executing in concurrent goroutines. 15 go func() { 16 time.Sleep(time.Second * 1) 17 c1 <- "one" 18 }() 19 go func() { 20 time.Sleep(time.Second * 2) 21 c2 <- "two" 22 }() 23 24 // We'll use `select` to await both of these values 25 // simultaneously, printing each one as it arrives. 26 for i := 0; i < 2; i++ { 27 select { 28 case msg1 := <-c1: 29 fmt.Println("received", msg1) 30 case msg2 := <-c2: 31 fmt.Println("received", msg2) 32 } 33 } 34 }
5、相关文章
Go非阻塞通道操作实例:使用select
和default
子句来实现非阻塞发送,接收
Go关闭通道实例:close直接关闭通道
Go通道范围实例:通道关闭了,还可以接收通道中的数据