go语言并发编程

文章目录

    • go并发
    • 通道
    • select分支语句

go语言教程:

  • 安装入门➡️for循环➡️数组、切片和指针➡️switch和map
  • 函数进阶➡️结构体、接口、面向对象➡️包管理和变量保护

go并发

go以高并发语言著称,而在go语言中,关键字go就是开启多线程的关键,下面做一个示例如下

//goTest.go
package main

import (
    "fmt"
    "time"
)

func count(s string) {
	for i := 0; i < 3; i++ {
		time.Sleep(100 * time.Millisecond)
        fmt.Println(s, i)
    }
}

func main() {
    go count("A:")
    count("B:")
}

其中,count是一个非常简单的函数,每间隔100毫秒就打印一个数字。在主函数中,先用go开启一个线程运行count(“A:”),然后用主线程运行count(“B”),运行结果如下

>go run goTest.go
B: 0
A: 0
A: 1
B: 1
B: 2

这里反映出两个现象,首先A和B的确是交替执行的,但A最后输出的数值是1,换言之,用go指令开启的线程,会在主线程结束之后自动销毁。

通道

并发的最大问题是线程通信,go语言为此打造了一种特殊的数据类型chan,即通道。而通道的通信方式,则经由一个特殊的操作符<-,形如c <- d的表达式,意味着将d的值传递给通道c;反过来说,d <- c则是将通道c传递过来的内容复制给d。

下面对count函数稍加改动,为其新增一个通道变量c,并且在循环时并不直接打印变量,而是将其内容输出给c

相应地,主函数也进行更改,并打印通道c中接收到的内容。

// chanTest.go
package main
import (
    "fmt"
    "time"
)

func count(s string, c chan string) {
	for i := 0; i < 3; i++ {
		time.Sleep(100 * time.Millisecond)
        c <- fmt.Sprintf("%s%d", s, i)
    }
}


func main() {
    c := make(chan string)
	go count("A:", c);
	go count("B:", c);
	for i:=0; i<3; i++{
	    x, y := <-c, <-c // 从通道 c 中接收
	    fmt.Println(x, y)
	}
}

运行结果如下

>go run chanTest.go
B:0 A:0
B:1 A:1
A:2 B:2

select分支语句

select...case是一种为了并发通信而设计的分支结构,其语法格式与switch如出一辙,但case后面必须是一个通道的通信操作。

下面用这个结构,来做一个斐波那契数列的生成函数,代码内容如下

// select.go
package main
import "fmt"
func fib(c,quit chan int){
	x,y:=0,1
	for{
		select{
		case c <- x: x,y = y, x+y
		case <-quit: return
		}
	}
}

func fibTo(N int, c,quit chan int){
	for i := 0; i < N; i++{
		fmt.Println(<-c)
	}
	quit <- 0
}

func main(){
	c := make(chan int)
	quit := make(chan int)
	go fibTo(15, c, quit)
	fib(c,quit)
}

其中,fib函数有两个输入参数,分别是通道c和quit,当c发送数据数据时,执行斐波那契过程;当quit受到数据时,跳出死循环。

fibTo函数除了这两个通道之外,还有一个整数N,表示斐波那契数列的终止下标。其内部只有一个循环,无需多言,当循环执行结束后,向quit通道发送一个0,这时fib函数中的select…case就进入到了quit接收,从而跳出。

其运行结果为

>go run select.go
0
1
1
2
3
5
8
13
21
34
55
89
144
233
377

你可能感兴趣的:(编程语言学习,golang,go语言,select...case,通道,go,并发,多线程)