go语言学习笔记 之 协程(goroutine)

特点

  1. go主线程是一个物理线程,直接作用在CPU上,重量级,非常耗费CPU资源
  2. 协程是从主线程开启的,是轻量级的线程,是逻辑态,资源消耗相对较小
  3. go可以轻松开启上万个协程

MPG

  • M: 操作系统的主线程
  • P: 协程执行需要的上下文环境
  • G: 协程
    当多个主线程运行在一个CPU核中,认为该状态为并发
    当多个主线程运行在多个CPU核中,认为该状态为并行

使用

  • 支持使用runtime.GOMAXPROCS方法设置使用的CPU核数
package main

import (
	"fmt"
	"strconv"
	"time"
)

func main() {
	// 启动协程
	go test()
	// 继续主线程
	for i := 1; i <= 10; i++ {
		fmt.Println("main() ..." + strconv.Itoa(i))
		time.Sleep(time.Second)
	}
}

func test() {
	for i := 1; i <= 10; i++ {
		fmt.Println("test() ..." + strconv.Itoa(i))
		time.Sleep(time.Second)
	}
}

注意:如果协程异常,抛出panic,会影响到主线程

结果

main() ...1
test() ...1
test() ...2
main() ...2
test() ...3
main() ...3
main() ...4
test() ...4
test() ...5
main() ...5
main() ...6
test() ...6
test() ...7
main() ...7
test() ...8
main() ...8
main() ...9
test() ...9
main() ...10
test() ...10

资源竞争

多线程计算阶乘

使用锁解决
package main

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

var (
	myMap = make(map[int64]int64, 10)
	// 全局互斥锁
	lock sync.Mutex
)

func Factorial(n int64) {
	var res int64 = 1
	var i int64
	for i = 1; i <= n; i++ {
		res *= i
	}

	lock.Lock()
	myMap[n] = res
	lock.Unlock()
}

func main() {
	for i := 0; i < 20; i++ {
		go Factorial(int64(i))
	}

	time.Sleep(time.Second * 10)

	lock.Lock()
	for k, v := range myMap {
		fmt.Println(k, "=", v)
	}
	lock.Unlock()
}

结果

4 = 24
11 = 39916800
8 = 40320
10 = 3628800
2 = 2
12 = 479001600
13 = 6227020800
0 = 1
5 = 120
3 = 6
7 = 5040
14 = 87178291200
18 = 6402373705728000
1 = 1
6 = 720
9 = 362880
19 = 121645100408832000
17 = 355687428096000
15 = 1307674368000
16 = 20922789888000

使用go build -race main.go查看并发资源竞争

使用channel解决(推荐)

channel本质是一个线程安全的队列,channel是引用类型

管道的使用

// 使用:var 变量名 chan 队列内元素类型
var myChan chan int = make(chan int, 10)
// 向管道写入数据
myChan <- 10
// 从管道读取数据
var num2 int = <- myChan

// 管道可以声明为只读或者只写的,默认是双向的,既可写又可读 
// 只写的管道
var myChan chan<- int 

// 只读的管道
var myChan <-chan int 

// 使用select防止管道阻塞
for {
	select {
		case v := <- myChan :
			fmt.Println(v)
		case v := <- myChan2 :
			fmt.Println(v)
		default :
			fmt.Println("暂时没有数据。。。")
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值