• go语言并发编程


    go语言教程:

    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:")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

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

    >go run goTest.go
    B: 0
    A: 0
    A: 1
    B: 1
    B: 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这里反映出两个现象,首先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)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    运行结果如下

    >go run chanTest.go
    B:0 A:0
    B:1 A:1
    A:2 B:2
    
    • 1
    • 2
    • 3
    • 4

    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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    其中,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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    Java开发面试--群面专区
    数仓工具—Hive集成篇之UDF写ES(04)
    Linux运维Centos7_创建虚拟机 安装操作系统
    协同办公系统OA实施过程中需要注意的细节
    制作一个简单的HTML个人网页
    表单设计器附件的上传、显示和下载
    [可视化] 点云可视化工具open3d的使用
    Buildroot 开发
    Python 类型注解
    stream流操作,获取List 集合中某一字段并求和
  • 原文地址:https://blog.csdn.net/m0_37816922/article/details/133767900