20 05 2025
package main

import (
"fmt"
"sync"
"time"
)

var wg sync.WaitGroup  //引入sync包的WaitGroup
var locks sync.Mutex   //引入sync包的Mutex   互斥锁
var wlock sync.RWMutex //引入sync包的RWMutex 读写锁
func test1() {
for i := 0; i < 10; i++ {
fmt.Println("test1:hello world", i)
time.Sleep(100 * time.Millisecond) //休眠100毫秒
}
wg.Done() // 减少一个协程
}
func test2() {
for i := 0; i < 10; i++ {
fmt.Println("test2:hello world", i)
time.Sleep(100 * time.Millisecond) //休眠100毫秒
}
wg.Done() // 减少一个协程
}

// 写入管道
func write_in(ch chan<- int) {
for i := 1; i <= 10; i++ {
ch <- i
fmt.Println("写入:", i)
time.Sleep(time.Millisecond * 100)
}
close(ch) //关闭管道 使得for range 结束 使用for循环 就不需要关闭管道
wg.Done() // 减少一个协程
}

// 读取管道
func read_out(ch <-chan int) {
for v := range ch {
fmt.Println("读取:", v)
time.Sleep(time.Millisecond * 100)
}
wg.Done() // 减少一个协程
}

// 存放数字 1-120000
func putnum(ch chan int) {
for i := 2; i <= 120000; i++ {
ch <- i
}
close(ch)
wg.Done()
}

// 存放素数
func primenum(ch chan int, ch2 chan int, ch3 chan bool) {
for v := range ch {
var flag = true
for i := 2; i < v; i++ {
if v%i == 0 {
flag = false
break
}
}
//是素数 写入素数管道
if flag {
ch2 <- v
}
}
// 状态管道存放值
ch3 <- true
wg.Done()

}

// 打印素数
func printprime(ch chan int) {
// for v := range ch {
// fmt.Println("素数:", v)
// }
wg.Done()
}

var count = 0

func countadd() {
locks.Lock() //加锁
c := &count
*c += 1
locks.Unlock() //解锁 解决资源互斥问题
wg.Done()
//wlock.Lock() //加写锁
//wlock.Unlock() //解写锁
//wlock.RLock() //加读锁
//wlock.RUnlock() //解读锁
//读写锁 读锁和写锁互斥 并发读 顺序写
}

func main() {
//进程就是一个正在执行的程序
//线程是进程的一个执行实例,是程序执行的最小单元,一个进程可以有多个线程,同一个进程中的多个线程可以并发执行
//并发:同一时间段内交替处理多个任务,通过快速切换任务实现“看似同时”的执行效果,微观上任务仍是顺序执行的14。例如单核CPU通过时间片轮转处理多个程序
// wg.Add(1) // 增加一个协程
// go test1() //启用一个协程,调用test函数 与主线程并行执行 要在执行主线程代码之前开启协程
// wg.Add(1) // 增加一个协程
// go test2() //启用一个协程,调用test函数 与主线程并行执行 要在执行主线程代码之前开启协程
// //每100毫秒输出一次hello world
// for i := 0; i < 10; i++ {
// fmt.Println("main:hello world", i)
// time.Sleep(50 * time.Millisecond) //休眠50毫秒
// }
// // 主线程执行完毕之后 协程会终止执行,要想协程执行完 需要协程在主线程之前或者同时执行完毕 或者使用sync.WaitGroup
// //等待所有协程执行完毕
// wg.Wait()
// // 主线程执行完毕
// fmt.Println("main:all done")

//获取当前计算机的逻辑CPU数
// cpunum := runtime.NumCPU()
// fmt.Println("main:cpu num:", cpunum)
//设置进程使用的cpu数量
// runtime.GOMAXPROCS(cpunum - 1)

// var ch chan int
// 管道是引用类型 用make 声明 类似队列
// ch := make(chan int, 10)
// // 向管道中写入数据
// ch <- 10
// // 取值 先入先出
// ch_v := <-ch
// // 在没有使用携程的情况下 管道没有值 继续取值 会阻塞
// // <-ch
// fmt.Printf("ch_v:%v,类型:%T\n", ch_v, ch_v)
// for i := 1; i <= 10; i++ {
// ch <- i
// }
// fmt.Printf("容量:%v,长度:%v\n", cap(ch), len(ch))
// //for range 遍历管道中的数据 管道中没有key
// close(ch) //关闭管道 使得for range 结束 使用for循环 就不需要关闭管道
// for v := range ch {
// fmt.Println("ch_v:", v)
// }

// ch := make(chan int, 10)
// wg.Add(2)
// go write_in(ch) //启用一个协程,向管道中写入数据
// go read_out(ch) //启用一个协程,从管道中读取数据
// //管道中的数据 写入 读取始终平衡
// wg.Wait() //等待所有协程执行完毕
// fmt.Println("main:all done")

//素数协程
// start := time.Now().Unix()
// //存放数字
// intchan := make(chan int, 1000)
// //存放素数
// primechan := make(chan int, 50000)
// //存放素数的管道运行状态
// primestatus := make(chan bool, 16)
// wg.Add(1)
// //存放数字的协程
// go putnum(intchan)
// //存放素数的协程
// for i := 0; i < 16; i++ {
// wg.Add(1)
// go primenum(intchan, primechan, primestatus)
// }
// //打印素数的协程
// wg.Add(1)
// go printprime(primechan)
// //判断存放素数的管道是否运行完毕
// wg.Add(1)
// go func() {
// for i := 0; i < 16; i++ {
// <-primestatus
// }
// //状态管道执行完 关闭素数管道
// close(primechan)
// wg.Done()
// }()
// wg.Wait()
// end := time.Now().Unix()
// fmt.Println("main:all done", end-start)

//双向管道 发送和接收可以同时进行
// ch1 := make(chan int, 10)
// ch1 <- 1
// ch1 <- 2
// a := <-ch1
// b := <-ch1
// fmt.Println(a, b)
// close(ch1)
// //单向管道 只写不读 或者 只读不写 不能同时进行
// ch2 := make(chan <-int,2) //只写
// ch2 <- 1
// ch3 := make( <-chan int,2) //只读

//select 语句 用于多路复用 使用多路复用可以同时监控多个通道的数据流动情况 并且不用关闭管道
// ch1 := make(chan int, 10)
// ch2 := make(chan int, 10)
// ch3 := make(chan int, 10)
// for i := 1; i <= 10; i++ {
// ch1 <- i
// ch2 <- i * 2
// ch3 <- i * 3
// }
// for {
// select {
// case v := <-ch1:
// fmt.Println("ch1", v)
// case v := <-ch2:
// fmt.Println("ch2", v)
// case v := <-ch3:
// fmt.Println("ch3", v)
// default:
// fmt.Println("default")
// //退出
// return
// }
// }

//defer自执行函数 + recover捕获异常 可以在协程中使用 不中断协程的执行 捕获异常 打印日志 继续执行

//测试协程的竞争关系
for i := 0; i < 200; i++ {
wg.Add(1)
go countadd()
}
wg.Wait()
fmt.Println("count:", count)
}

延伸阅读
学习golang(七)
学习golang(四)
学习golang(伍)
golang连接数据库 增删改查以及事物
golang使用gorm 操作数据库
发表评论
最新|与我有关