package main
import (
"fmt"
"time"
)
// 在主线程(可以理解成进程)中,开启一个goroutine, 该协程每隔50毫秒秒输出 "你好golang"
// 在主线程中也每隔50毫输出"你好golang", 输出10次后,退出程序
// 要求主线程和goroutine同时执行
func test() {
for i := 0; i < 10; i++ {
fmt.Println("test() 你好golang")
time.Sleep(time.Millisecond * 100)
}
}
func main() {
go test() //表示开启一个协程
for i := 0; i < 10; i++ {
fmt.Println("main() 你好golang")
time.Sleep(time.Millisecond * 100)
}
}
package main
import (
"fmt"
"sync"
"time"
)
//主线程退出后所有的协程无论有没有执行完毕都会退出,所以我们在主进程中可以通过WaitGroup等待协程执行完毕
var wg sync.WaitGroup
func test1() {
for i := 0; i < 10; i++ {
fmt.Println("test1() 你好golang-", i)
time.Sleep(time.Millisecond * 100)
}
wg.Done() //协程计数器-1
}
func test2() {
for i := 0; i < 10; i++ {
fmt.Println("test2() 你好golang-", i)
time.Sleep(time.Millisecond * 100)
}
wg.Done() //协程计数器-1
}
func main() {
wg.Add(1) //协程计数器+1
go test1() //表示开启一个协程
wg.Add(1) //协程计数器+1
go test2() //表示开启一个协程
wg.Wait() //等待协程执行完毕...
fmt.Println("主线程退出...")
}
package main
import (
"fmt"
"runtime"
)
func main() {
//获取当前计算机上面的Cup个数
cpuNum := runtime.NumCPU()
fmt.Println("cpuNum=", cpuNum)
//可以自己设置使用多个cpu
runtime.GOMAXPROCS(cpuNum - 1)
fmt.Println("ok")
}
package main
import (
"fmt"
"sync"
"time"
)
//多携程的一个案例
var wg sync.WaitGroup
func test(num int) {
defer wg.Done()
for i := 1; i <= 5; i++ {
fmt.Printf("协程(%v)打印的第%v条数据\n", num, i)
time.Sleep(time.Millisecond * 100)
}
}
func main() {
for i := 1; i <= 6; i++ {
wg.Add(1)
go test(i)
}
wg.Wait()
fmt.Println("关闭主线程...")
}
package main
import (
"fmt"
"time"
)
//需求:要统计1-120000的数字中那些是素数?for循环实现
func main() {
start := time.Now().Unix()
for num := 2; num < 120000; num++ {
var flag = true
for i := 2; i < num; i++ {
if num%i == 0 {
flag = false
break
}
}
if flag {
// fmt.Println(num, "是素数")
}
}
end := time.Now().Unix()
fmt.Println(end - start) //11毫秒 11毫秒
}
package main
import (
"fmt"
"sync"
"time"
)
//需求:要统计1-120000的数字中那些是素数?goroutine for循环实现
/*
1 协程 统计 1-30000
2 协程 统计 30001-60000
3 协程 统计 60001-90000
4 协程 统计 90001-120000
// start:(n-1)*30000+1 end:n*30000
*/
var wg sync.WaitGroup
func test(n int) {
for num := (n-1)*30000 + 1; num < n*30000; num++ {
if num > 1 {
var flag = true
for i := 2; i < num; i++ {
if num%i == 0 {
flag = false
break
}
}
if flag {
// fmt.Println(num, "是素数")
}
}
}
wg.Done()
}
func main() {
start := time.Now().Unix()
for i := 1; i <= 4; i++ {
wg.Add(1)
go test(i)
}
wg.Wait()
fmt.Println("执行完毕")
end := time.Now().Unix()
fmt.Println(end - start) //4毫秒
}
package main
import "fmt"
func main() {
//1、创建channel
ch := make(chan int, 3)
//2、给管道里面存储数据
ch <- 10
ch <- 21
ch <- 32
//3、获取管道里面的内容
a := <-ch
fmt.Println(a) //10
<-ch //从管道里面取值 //21
c := <-ch
fmt.Println(c) //32
ch <- 56
ch <- 66
//4、打印管道的长度和容量
fmt.Printf("值:%v 容量:%v 长度%v\n", ch, cap(ch), len(ch)) //值:0xc0000d0080 容量:3 长度2
// 5、管道的类型(引用数据类型)
ch1 := make(chan int, 4)
ch1 <- 34
ch1 <- 54
ch1 <- 64
ch2 := ch1
ch2 <- 69
<-ch1
<-ch1
<-ch1
d := <-ch1
fmt.Println(d) //69
//8、管道阻塞
// ch6 := make(chan int, 1)
// ch6 <- 34
// ch6 <- 64 //all goroutines are asleep - deadlock!
// 在没有使用协程的情况下,如果我们的管道数据已经全部取出,再取就会报告 deadlock
// ch7 := make(chan string, 2)
// ch7 <- "数据1"
// ch7 <- "数据2"
// m1 := <-ch7
// m2 := <-ch7
// m3 := <-ch7
// fmt.Println(m1, m2, m3) //fatal error: all goroutines are asleep - deadlock!
//正确的写法
ch8 := make(chan int, 1)
ch8 <- 34
<-ch8
ch8 <- 67
<-ch8
ch8 <- 78
m4 := <-ch8
fmt.Println(m4)
}
package main
import "fmt"
// 循环遍历管道数据
func main() {
//2、使用for range遍历通道,当通道被关闭的时候就会退出for range,如果没有关闭管道就会报个错误fatal error: all goroutines are asleep - deadlock!
// var ch1 = make(chan int, 10)
// for i := 1; i <= 10; i++ {
// ch1 <- i
// }
// close(ch1) //关闭管道
// //for range循环遍历管道的值 ,注意:管道没有key
// for v := range ch1 {
// fmt.Println(v)
// }
//2、通过for循环遍历管道的时候管道可以不关闭
var ch2 = make(chan int, 10)
for i := 1; i <= 10; i++ {
ch2 <- i
}
for j := 0; j < 10; j++ {
fmt.Println(<-ch2)
}
}
package main
import (
"fmt"
"sync"
)
package main
var wg sync.WaitGroup
func putNum(intChan chan int) {
for i := 2; i < 10; i++ {
intChan <- i
fmt.Println(i)
}
close(intChan)
wg.Done()
}
//定义一个存放任意数据类型的管道 3个数据
func main() {
// allChan := make(chan interface{}, 3)
// allChan <- 10
// allChan <- "tom jack"
// cat := Cat{"小花猫", 4}
// allChan <- cat
// //我们希望获得到管道中的第三个元素,则先将前2个推出
// <-allChan
// <-allChan
// newCat := <-allChan //从管道中取出的Cat是什么?
// fmt.Printf("newCat=%T , newCat=%v\n", newCat, newCat)
// //下面的写法是错误的!编译不通过
// //fmt.Printf("newCat.Name=%v", newCat.Name)
// //使用类型断言
// a := newCat.(Cat)
// fmt.Printf("newCat.Name=%v", a.Name)
var intChan = make(chan int, 1000)
wg.Add(1)
go putNum()
wg.Wait()()
}
package main
import (
"fmt"
"sync"
"time"
)
/*
需求:使用goroutine和channel协同工作案例
1、开启一个WriteData的的协程给向管道inChan中写入100条数据
2、开启一个ReadData的协程读取inChan中写入的数据
3、注意:WriteData和ReadData同时操作一个管道
4、主线程必须等待操作完成后才可以退出
goroutine结合Channel使用的简单demo,定义两个方法,一个方法给管道里面写数据,一个给管道里面读取数据。要求同步进行。
*/
var wg sync.WaitGroup
//写数据
func fn1(ch chan int) {
for i := 1; i <= 10; i++ {
ch <- i
fmt.Printf("【写入】数据%v成功\n", i)
time.Sleep(time.Millisecond * 5000)
}
close(ch)
wg.Done()
}
func fn2(ch chan int) {
for v := range ch {
fmt.Printf("【读取】数据%v成功\n", v)
time.Sleep(time.Millisecond * 10)
}
wg.Done()
}
func main() {
var ch = make(chan int, 10)
wg.Add(1)
go fn1(ch)
wg.Add(1)
go fn2(ch)
wg.Wait()
fmt.Println("退出...")
}
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func main() {
// 1、创建channel
var ch1 = make(chan int, 3)
wg.Add(1)
go func() {
for i := 1; i <= 3; i++ {
num := <-ch1
fmt.Println(num)
}
wg.Done()
}()
wg.Add(1)
go func() {
for i := 1; i <= 3; i++ {
time.Sleep(time.Second)
ch1 <- i
}
wg.Done()
}()
wg.Wait()
}
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
//向 intChan放入 1-120000个数
func putNum(intChan chan int) {
for i := 2; i < 120000; i++ {
intChan <- i
}
close(intChan)
wg.Done()
}
// 从 intChan取出数据,并判断是否为素数,如果是,就把得到的素数放在primeChan
func primeNum(intChan chan int, primeChan chan int, exitChan chan bool) {
for num := range intChan {
var flag = true
for i := 2; i < num; i++ {
if num%i == 0 {
flag = false
break
}
}
if flag {
primeChan <- num //num是素数
}
}
//要关闭 primeChan
// close(primeChan) //如果一个channel关闭了就没法给这个channel发送数据了
//什么时候关闭primeChan?
//给exitChan里面放入一条数据
exitChan <- true
wg.Done()
}
//printPrime打印素数的方法
func printPrime(primeChan chan int) {
// for v := range primeChan {
// fmt.Println(v)
// }
wg.Done()
}
func main() {
start := time.Now().Unix()
intChan := make(chan int, 1000)
primeChan := make(chan int, 50000)
exitChan := make(chan bool, 16) //标识primeChan close
//存放数字的协程
wg.Add(1)
go putNum(intChan)
//统计素数的协程
for i := 0; i < 16; i++ {
wg.Add(1)
go primeNum(intChan, primeChan, exitChan)
}
//打印素数的协程
wg.Add(1)
go printPrime(primeChan)
//判断exitChan是否存满值
wg.Add(1)
go func() {
for i := 0; i < 16; i++ {
<-exitChan
}
//关闭primeChan
close(primeChan)
wg.Done()
}()
wg.Wait()
end := time.Now().Unix()
fmt.Println("执行完毕....", end-start, "毫秒")
}
package main
import "fmt"
//单向管道
func main() {
// 1、在默认情况下下,管道是双向
ch1 := make(chan int, 2)
ch1 <- 10
ch1 <- 12
m1 := <-ch1
m2 := <-ch1
fmt.Println(m1, m2) //10 12
// 2、管道声明为只写
ch2 := make(chan<- int, 2)
ch2 <- 10
ch2 <- 12
// <-ch2 //receive from send-only type chan<- int
// 3、管道声明为只读
ch3 := make(<-chan int, 2)
// ch3 <- 23
}
package main
import (
"fmt"
"sync"
"time"
)
/*
需求:使用goroutine和channel协同工作案例
1、开启一个WriteData的的协程给向管道inChan中写入100条数据
2、开启一个ReadData的协程读取inChan中写入的数据
3、注意:WriteData和ReadData同时操作一个管道
4、主线程必须等待操作完成后才可以退出
goroutine结合Channel使用的简单demo,定义两个方法,一个方法给管道里面写数据,一个给管道里面读取数据。要求同步进行。
*/
var wg sync.WaitGroup
//写数据
func fn1(ch chan<- int) {
for i := 1; i <= 10; i++ {
ch <- i
fmt.Printf("【写入】数据%v成功\n", i)
time.Sleep(time.Millisecond * 50)
}
close(ch)
wg.Done()
}
//读取管道里面的数据
func fn2(ch <-chan int) {
for v := range ch {
fmt.Printf("【读取】数据%v成功\n", v)
time.Sleep(time.Millisecond * 50)
}
wg.Done()
}
func main() {
var ch = make(chan int, 10)
wg.Add(1)
go fn1(ch)
wg.Add(1)
go fn2(ch)
wg.Wait()
fmt.Println("退出...")
}
package main
import (
"fmt"
"time"
)
func main() {
// 在某些场景下我们需要同时从多个通道接收数据,这个时候就可以用到golang中给我们提供的select多路复用
//1.定义一个管道 10个数据int
intChan := make(chan int, 10)
for i := 0; i < 10; i++ {
intChan <- i
}
//2.定义一个管道 5个数据string
stringChan := make(chan string, 5)
for i := 0; i < 5; i++ {
stringChan <- "hello" + fmt.Sprintf("%d", i)
}
//使用select来获取channel里面的数据的时候不需要关闭channel
for {
select {
case v := <-intChan:
fmt.Printf("从 intChan 读取的数据%d\n", v)
time.Sleep(time.Millisecond * 50)
case v := <-stringChan:
fmt.Printf("从 stringChan 读取的数据%v\n", v)
time.Sleep(time.Millisecond * 50)
default:
fmt.Printf("数据获取完毕")
return //注意退出...
}
}
}
package main
import (
"fmt"
"time"
)
//函数
func sayHello() {
for i := 0; i < 10; i++ {
time.Sleep(time.Millisecond * 50)
fmt.Println("hello,world")
}
}
//函数
func test() {
//这里我们可以使用defer + recover
defer func() {
//捕获test抛出的panic
if err := recover(); err != nil {
fmt.Println("test() 发生错误", err)
}
}()
//定义了一个map
var myMap map[int]string
myMap[0] = "golang" //error
}
func main() {
go sayHello()
go test()
//防止主进程退出这里使用time.Sleep演示,搭建也可以用sync.WaitGroup
time.Sleep(time.Second)
}
package main
//go build -race main.go 编译后运行查看
import (
"fmt"
"sync"
"time"
)
var count = 0
var wg sync.WaitGroup
var mutex sync.Mutex
func test() {
mutex.Lock()
count++
fmt.Println("the count is : ", count)
time.Sleep(time.Millisecond)
mutex.Unlock()
wg.Done()
}
func main() {
for r := 0; r < 20; r++ {
wg.Add(1)
go test()
}
wg.Wait()
}
package main
//go build -race main.go 编译后运行查看
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
var mutex sync.Mutex
var m = make(map[int]int, 0)
func test(num int) {
mutex.Lock()
var sum = 1
for i := 1; i <= num; i++ {
sum *= i
}
m[num] = sum
// fmt.Println(m[num])
fmt.Printf("key=%v value=%v\n", num, sum)
time.Sleep(time.Millisecond)
mutex.Unlock()
wg.Done()
}
func main() {
for r := 0; r < 40; r++ {
wg.Add(1)
go test(r)
}
wg.Wait()
}
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
var mutex sync.RWMutex
//写的方法
func write() {
mutex.Lock()
fmt.Println("执行写操作")
time.Sleep(time.Second * 2)
mutex.Unlock()
wg.Done()
}
//读的方法
func read() {
mutex.RLock()
fmt.Println("---执行读操作")
time.Sleep(time.Second * 2)
mutex.RUnlock()
wg.Done()
}
func main() {
//开启10个协程执行读操作
for i := 0; i < 10; i++ {
wg.Add(1)
go write()
}
// 开启10个协程执行写操作
for i := 0; i < 10; i++ {
wg.Add(1)
go read()
}
wg.Wait()
}