【Go语言】Goroutine总结
Goroutine是什么意思?
并发处理的意思。用其他语言来说就是多线程。
49个Goroutine和Sync.WaitGroup
如果要同时运行normal()和goroutine(),则需要在其中一个方法前加上go进行执行。
package main
import (
"fmt"
"time"
)
func goroutine(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func normal(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go goroutine("world")
normal("hello")
}
hello
world
world
hello
hello
world
world
hello
hello
在这里,如果注释掉time,只会显示normal()的执行结果。
生成一个线程,在goroutine()执行之前,normal()就会结束。
package main
import (
"fmt"
)
func goroutine(s string) {
for i := 0; i < 5; i++ {
// time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func normal(s string) {
for i := 0; i < 5; i++ {
// time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go goroutine("world")
normal("hello")
}
hello
hello
hello
hello
hello
要执行并行处理,需要按照以下步骤进行。
package main
import (
"fmt"
"sync"
)
func goroutine(s string, wg *sync.WaitGroup) {
for i := 0; i < 5; i++ {
fmt.Println(s)
}
wg.Done()
}
func normal(s string) {
for i := 0; i < 5; i++ {
fmt.Println(s)
}
}
func main() {
var wg sync.WaitGroup
wg.Add(1)
go goroutine("world", &wg)
normal("hello")
wg.Wait()
}
在wg的Add()函数中声明有一个并行处理,Wait()函数将一直等待直到Done()函数被执行。
50个频道
package main
import (
"fmt"
)
func goroutine1(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum
}
func goroutine2(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum
}
func normal(s string) {
for i := 0; i < 5; i++ {
fmt.Println(s)
}
}
func main() {
s := []int{1, 2, 3, 4, 5}
c := make(chan int)
go goroutine1(s, c)
go goroutine2(s, c)
x := <-c
fmt.Println((x))
y := <-c
fmt.Println((y))
}
15
15
声明一个通道,并将其传递给goroutine1()和goroutine2()。将结果放入通道,并将返回的值存入变量后输出。
51个缓冲通道
package main
import (
"fmt"
)
func main() {
ch := make(chan int, 2)
ch <- 100
fmt.Println(len(ch))
ch <- 200
fmt.Println(len(ch))
close(ch)
for c := range ch {
fmt.Println(c)
}
}
在创建channel时,如果在make()函数的第二个参数中指定一个数字,就可以指定可放入channel的数量。
如果尝试向channel中放入超过指定数量的值,将会产生错误。
另外,在从chennel中使用for循环取出时,如果没有执行close()会出现错误。
这是因为在本例中,取出了两个值之后又尝试取出第三个值。
53个制造者和消费者
我对此的理解程度还不够深。在生成的生产者和消费者之间,进行一系列ch的交互,然后执行处理。
package main
import (
"fmt"
"sync"
)
func producer(ch chan int, i int) {
ch <- i * 2
}
func consumer(ch chan int, wg *sync.WaitGroup) {
for i := range ch {
func() {
wg.Done()
fmt.Println("process", i*1000)
}()
}
fmt.Println("##################")
}
func main() {
var wg sync.WaitGroup
ch := make(chan int)
// Producer
for i := 0; i < 10; i++ {
wg.Add(1)
go producer(ch, i)
}
// Consumer
go consumer(ch, &wg)
wg.Wait()
close(ch)
}
选择55个频道
package main
import (
"fmt"
"time"
)
func goroutine1(ch chan string) {
for {
ch <- "packet from 1"
time.Sleep(3 * time.Second)
}
}
func goroutine2(ch chan int) {
for {
ch <- 100
time.Sleep(1 * time.Second)
}
}
func main() {
c1 := make(chan string)
c2 := make(chan int)
go goroutine1(c1)
go goroutine2(c2)
for {
select {
case msg1 := <-c1:
fmt.Println(msg1)
case msg2 := <-c2:
fmt.Println(msg2)
}
}
}
在不同的goroutine中执行处理,并根据它们的结果进行分支选择时,请使用select。
56 默认选择和中断
package main
import (
"fmt"
"time"
)
func main() {
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
OuterLoop:
for {
select {
case <-tick:
fmt.Println("tick.")
case <-boom:
fmt.Println("BOOM")
break OuterLoop
default:
fmt.Println(" .")
time.Sleep(50 * time.Millisecond)
}
}
fmt.Println("###############")
}
将outerloop声明在for循环之外,并在break语句后指定它,这样可以指定要从哪个循环中跳出。
time.Tick会返回一个通道。