网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
func test(){
for i:=0;i<10;i++{
time.Sleep(time.Second)
fmt.Println("hello world")
}
}
func main() {
go test()
for i:=0;i<10;i++{
time.Sleep(time.Second)
fmt.Println("hello golang")
}
}
2、总结:
- 主线程是一个物理线程,直接作用在 cpu 上的。是重量级的,非常耗费 cpu 资源。
- 协程从主线程开启的,是轻量级的线程,是逻辑态。对资源消耗相对小。
- Golang 的协程机制是重要的特点,可以轻松的开启上万个协程。其它编程语言的并发机制是一
般基于线程的,开启过多的线程,资源耗费大,这里就突显 Golang 在并发上的优势了
三、channel使用
1、为什么用channel
异步累加案例:
var s =0
func sum(a int){
s+=a
}
func main() {
for i:=0;i<100;i++{
go sum(i)
}
time.Sleep(time.Second\*2)
fmt.Println(s)
}
每次执行出现的结果可能会不一样
问题一、什么时候累加结束?
问题二、协程A累加后的s值会覆盖协程B累加后的s值吗?
如何解决?
- 全局变量的互斥锁
- 使用管道 channel 来解决
2、全局变量的互斥锁
对s进行加锁,并加入n告诉程序什么时候累加结束。
var (
s = 0
n = 0
lock sync.Mutex
)
func sum(a int){
lock.Lock()
defer lock.Unlock()
s+=a
n++
}
func main() {
for i:=0;i<100;i++{
go sum(i)
}
for{
if n == 100{
break
}
}
fmt.Println(s)
}
似乎这个已经完美解决了所有问题。但是我们使用线程的目的是什么?效率
- 加锁了就是要等依次执行,协程A执行完成加锁的代码才能让出资源供协程B执行
- 通过全局变量加锁同步来实现通讯,也并不利用多个协程对全局变量的读写操作。
这里就需要使用channel了
3、channel 的基本介绍
- channle 本质就是一个数据结构-队列【示意图】
- 数据是先进先出【FIFO : first in first out】
- 线程安全,多 goroutine 访问时,不需要加锁,就是说 channel 本身就是线程安全的
- channel 有类型的,一个 string 的 channel 只能存放 string 类型数据。
- 示意图:
4、定义/声明 channel
var 变量名 chan 数据类型
举例:
var intChan chan int (intChan 用于存放 int 数据)
var mapChan chan map[int]string (mapChan 用于存放 map[int]string 类型)
var perChan chan Person
var perChan2 chan \*Person
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)**
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!