Go-并发编程基础(goroutine、channel、select等)_goroutine select

给大家的福利

零基础入门

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

同时每个成长路线对应的板块都有配套的视频提供:

在这里插入图片描述

因篇幅有限,仅展示部分资料

网络安全面试题

绿盟护网行动

还有大家最喜欢的黑客技术

网络安全源码合集+工具包

所有资料共282G,朋友们如果有需要全套《网络安全入门+黑客进阶学习资源包》,可以扫描下方二维码领取(如遇扫码问题,可以在评论区留言领取哦)~

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以点击这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

for i:=0;i<3;i++{
	fmt.Println("routinetest",i,":hello,",name)
	time.Sleep(100*time.Millisecond)
}

}

func main() {
num :=runtime.NumCPU()
fmt.Println(num)
runtime.GOMAXPROCS(num)
//runtime.GOMAXPROCS(1)
//--------使用go开启协程----------
go routinetest(“lady”)
go routinetest(“killer”)
time.Sleep(time.Second)
}


可以通过runtime.GOMAXPROCS设置cpu数,这里设置成了8个。


![](https://img-blog.csdnimg.cn/20210907165353640.PNG?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAbGFkeV9raWxsZXI5,size_18,color_FFFFFF,t_70,g_se,x_16)


## 通道Channel


相对于sync的低水平同步,使用channel可以实现高水平同步,channel是**先进先出**的。


### 数据结构


Channel 在运行时的内部表示是 [runtime.hchan](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb),该结构体中包含了用于保护成员变量的**互斥锁**,从某种程度上说,Channel 是一个用于同步和通信的**有锁队列**,使用互斥锁解决程序中可能存在的线程竞争问题是很常见的,我们能很容易地实现有锁队列。



type hchan struct {
qcount uint
dataqsiz uint
buf unsafe.Pointer
elemsize uint16
closed uint32
elemtype *_type
sendx uint
recvx uint
recvq waitq
sendq waitq
lock mutex
}


[runtime.hchan](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb) 结构体中的五个字段 `qcount`、`dataqsiz`、`buf`、`sendx`、`recv` 构建底层的循环队列:


* `qcount` — Channel 中的元素个数;
* `dataqsiz` — Channel 中的循环队列的长度;
* `buf` — Channel 的缓冲区数据指针;
* `sendx` — Channel 的发送操作处理到的位置;
* `recvx` — Channel 的接收操作处理到的位置;


除此之外,`elemsize` 和 `elemtype` 分别表示当前 Channel 能够收发的元素类型和大小;`sendq` 和 `recvq` 存储了当前 Channel 由于缓冲区空间不足而阻塞的 Goroutine 列表,这些等待队列使用双向链表 [runtime.waitq](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb) 表示,链表中所有的元素都是 [runtime.sudog](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb) 结构:



type waitq struct {
first *sudog
last *sudog
}


[runtime.sudog](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb) 表示一个在等待列表中的 Goroutine,该结构中存储了两个分别指向前后 [runtime.sudog](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb) 的指针以构成链表。


### 声明&初始化


初始化需要使用make(t Type, size ...IntegerType) Type,size为缓存大小



> 
> 
> ```
> var b chan int
> var c = make(chan int)
> var d = make(chan int,10)
> ```
> 
> 


b为nil,c为无缓存channel,d为有缓存channel 


### 发送与接收


发送使用channel<-data,接收使用[var,ok]:=<-channel,当左侧没有变量接收时会直接丢弃掉数据,ok可以标识channel是否有数据,无数据是,接收变量获取到的是对应类型的零值。


对于nil的channel,发送和接收都会阻塞,所以不make的channel没有用,实际编程中channel应该都初始化


对于无缓存的channel,发送后会阻塞,直至接收


对于有缓存的channel,满了后发送会被阻塞,接收无影响


### 遍历和关闭


close


关闭后无法写入,只能读取,例如



close(d)


普通for循环



for j := 0;j<len(c); j++{
	fmt.Println(<-c)
}

若取的时候,没有其他goroutine写入的话,会读出一半。例如,刚开始len(c)是10个,当j为5时,len(c)也是5了,就跳出循环了。



for j := 0;len(c)!=0; j++{
	fmt.Println(<-c)
}

上面这种方法可以 


for range


**关闭后**可以正常遍历,遍历也是从channel中接收值,大小会变化,例如



for data := range d{
	fmt.Println(data)
}

若不关闭,会一直接收数据,即使当前channel没有数据了,无goroutine写入时会block,若是在main routine中,会导致deadlock错误。





 channel状态总结 
 | 动作\状态 | nil | 非空 | 空的 | 满了 | 没满 |
| --- | --- | --- | --- | --- | --- |
| 接收 | 阻塞 | 接收值 | 阻塞 | 接收值 | 接收值 |
| 发送         | 阻塞 | 发送值 | 发送值 | 阻塞 | 发送值 |
| 关闭 | **panic** | 关闭成功,读完数据后返回零值 | 关闭成功,返回零值 | 关闭成功,读完数据后返回零值 | 关闭成功,读完数据后返回零值 |


### 单方向的channel


只发送chan<-int


只接收



var in = make(chan <- int)
var out = make(<-chan int,3)


### channel中的channel



package main

import “fmt”

type Request struct{
num int
result chan int
}

func result(r Request) {
r.result <- r.num + 1
}

func main() {
r := Request{1,make(chan int)}
go result®
fmt.Println(<-r.result)
}


### 常见错误


panic: close of nil channel


关闭nil的channel


fatal error: all goroutines are asleep - deadlock!


main routine被永久阻塞,例如,接收一个空的channel,一直没有goroutine向里面放数据


panic: send on closed channel


向关闭的channel中发送数据


## time与select


select是针对并发特有的控制结构。和switch很像,但每个case不是表达式而是通信,当有多个case可以时,将伪随机选择一个,所以不能依赖select来做顺序通信。


### 超时



> 
> func After(d Duration) <-chan Time
> 
> 
> 


 到达一定时间后可以从channel接收数据



package main

import (
“fmt”
“math/rand”
“time”
)

func main() {
timeout := time.After(2*time.Second)
c := make(chan int)
go func() {
for {
c<-0
time.Sleep(time.Duration(rand.Intn(500))*time.Millisecond)
}
}()
for {
select {
case <-c:
fmt.Println(“I’m working…”)
case <-timeout:
fmt.Println(“time out”)
return
}
}
}



### 一、网安学习成长路线图


网安所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/aa7be04dc8684d7ea43acc0151aebbf1.png)


### 二、网安视频合集


观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/f0aeee2eec7a48f4ad7d083932cb095d.png)


### 三、精品网安学习书籍


当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/078ea1d4cda342f496f9276a4cda5fcf.png)


### 四、网络安全源码合集+工具包


光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/e54c0bac8f3049928b488dc1e5080fc5.png)


### 五、网络安全面试题


最后就是大家最关心的网络安全面试题板块  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/15c1192cad414044b4dd41f3df44433d.png)![在这里插入图片描述](https://img-blog.csdnimg.cn/b07abbfab1fd4edc800d7db3eabb956e.png)  



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化资料的朋友,可以点击这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值