【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会返回一个通道。

广告
将在 10 秒后关闭
bannerAds