Golang 并发编程

Golang 并发编程

Goroutine

什么是协程

创建 Goroutine

主 goroutine (main函数)退出后,其它的工作 goroutine 也会自动退出

go 复制代码
package main

import (
	"fmt"
	"time"
)

func myFunc() {
	i := 0
	for {
		i++
		fmt.Println("func: ", i)
		time.Sleep(1 * time.Second)
	}
}

func main() {
	go myFunc()
	i := 0
	for {
		i++
		fmt.Println("main: ", i)
		time.Sleep(1 * time.Second)
	}
}
bash 复制代码
main:  1
func:  1
func:  2
main:  2

Goexit 函数

调用 runtime.Goexit() 将立即终止当前 goroutine 执⾏

go 复制代码
func myFunc() {
	i := 0
	for {
		i++
		fmt.Println("func: ", i)
		time.Sleep(1 * time.Second)
		if i == 10 {
			fmt.Println("func OVER ~")
			runtime.Goexit()
		}
	}
}

func main() {
	go myFunc()
	i := 0
	for {
		i++
		fmt.Println("main: ", i)
		time.Sleep(1 * time.Second)
	}
}
bash 复制代码
...
func:  9
main:  9
main:  10
func:  10
func OVER ~
main:  11
main:  12
...

匿名函数

go 复制代码
func main() {
	func() {
		fmt.Println("hello, I don't have name.")
	}()
}
go 复制代码
func main() {
	fun := func() {
		fmt.Println("hello, I don't have name.")
	}
	fun()
}

Channel

什么是 Channel

channel 用来解决go程的同步问题以及go程之间数据共享(数据传递)的问题。

⽤类型 channel可用于多个 goroutine 通讯。其内部实现了同步,确保并发安全。

创建管道

go 复制代码
package main

import (
	"fmt"
	"time"
)

var c chan int

func f(name string) {
	for {
		i := <-c
		fmt.Println(name, ": ", i)
		i++
		c <- i
		time.Sleep(1 * time.Second)
	}
}

func main() {
	c = make(chan int)
	go f("fun1")
	go f("fun2")
	c <- 0
	for {
	}
}
shell 复制代码
fun2 :  0
fun1 :  1
fun2 :  2
fun1 :  3
fun2 :  4
fun1 :  5
fun2 :  6

Channel 的缓冲

无缓冲:通道不保存数据,生产者会等待消费者,将数据放到管道中。

有缓存:类似消息队列,可以保存在管道中。

go 复制代码
package main

import (
	"fmt"
	"time"
)

var c chan int

func f(name string) {
	for {
		i := <-c
		fmt.Println(name, ": ", i)
		i++
		c <- i
		time.Sleep(10 * time.Millisecond)
	}
}

func main() {
    // 有缓冲的 Channel
	c = make(chan int, 1)
	go f("fun1")
	go f("fun2")
	c <- 0
	time.Sleep(1 * time.Second)
}

会产生同一个 go 程会执行多次的效果

go 复制代码
func main() {
    // 无缓冲的 Channel
	c = make(chan int)
	go f("fun1")
	go f("fun2")
	c <- 0
	time.Sleep(1 * time.Second)
}

两个 go 程交替运行,channel 作为锁,相互阻塞线程。

关闭 channel

go 复制代码
package main
 
import (
    "fmt"
)
 
func main() {
    c := make(chan int)
 
    go func() {
        for i := 0; i < 5; i++ {
            c <- i
        }
        close(c)
    }()
 
    for {
        // ok为true说明channel没有关闭,为false说明管道已经关闭
        if data, ok := <-c; ok {
            fmt.Println(data)
        } else {
            break
        }
    }
 
    fmt.Println("Finished")
}

range 函数

可以用 range 迭代操作 channel

go 复制代码
package main
 
import (
    "fmt"
)
 
func main() {
    c := make(chan int)
 
    go func() {
        for i := 0; i < 5; i++ {
            c <- i
        }
        close(c)
    }()
 
    for data := range c {
        fmt.Println(data)
    }
    fmt.Println("Finished")
}

select 函数

用于多路监控 channel

go 复制代码
package main

import (
	"fmt"
)

func fibonacci(c, quit chan int) {
	x, y := 1, 1
	for {
		select {
		case c <- x:
			x, y = y, x+y
		case <-quit:
			fmt.Println("quit")
			return
		}
	}
}

func main() {
	c := make(chan int)
	quit := make(chan int)

	go func() {
		for i := 0; i < 6; i++ {
			fmt.Println(<-c)
		}
		quit <- 0
	}()

	fibonacci(c, quit)
}

Go Modules

配置

sh 复制代码
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct

创建项目

sh 复制代码
go mod init github.com/wmh1024/demo_module
go get xxxx

replace

修改模块的版本依赖关系

sh 复制代码
go mod edit -replace=zinx@v0.0.0-20200306023939-bc416543ae24=zinx@v0.0.0-20200221135252-8a8954e75100
相关推荐
爱吃喵的鲤鱼5 分钟前
linux进程的状态之环境变量
linux·运维·服务器·开发语言·c++
DARLING Zero two♡32 分钟前
关于我、重生到500年前凭借C语言改变世界科技vlog.16——万字详解指针概念及技巧
c语言·开发语言·科技
Gu Gu Study34 分钟前
【用Java学习数据结构系列】泛型上界与通配符上界
java·开发语言
芊寻(嵌入式)1 小时前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
AskHarries1 小时前
Java字节码增强库ByteBuddy
java·后端
一颗松鼠1 小时前
JavaScript 闭包是什么?简单到看完就理解!
开发语言·前端·javascript·ecmascript
有梦想的咸鱼_1 小时前
go实现并发安全hashtable 拉链法
开发语言·golang·哈希算法
海阔天空_20131 小时前
Python pyautogui库:自动化操作的强大工具
运维·开发语言·python·青少年编程·自动化
佳佳_1 小时前
Spring Boot 应用启动时打印配置类信息
spring boot·后端
天下皆白_唯我独黑1 小时前
php 使用qrcode制作二维码图片
开发语言·php