当前位置: 首页 > news >正文

海拉尔做网站的公司网站主题推荐

海拉尔做网站的公司,网站主题推荐,微信小游戏源码,简单的公司简介go的通道channel是用于协程之间数据通信的一种方式 一、channel的结构 go源码#xff1a;GitHub - golang/go: The Go programming language src/runtime/chan.go type hchan struct {qcount uint // total data in the queue 队列中当前元素计数#xff0c;…go的通道channel是用于协程之间数据通信的一种方式 一、channel的结构 go源码GitHub - golang/go: The Go programming language src/runtime/chan.go type hchan struct {qcount uint // total data in the queue 队列中当前元素计数满了就dataqsizdataqsiz uint // size of the circular queue 环形队列大小(缓存大小)buf unsafe.Pointer // points to an array of dataqsiz elements 指向任意类型的指针elemsize uint16 //元素大小closed uint32 //是否关闭,0-未关闭1-已关闭timer *timer // timer feeding this chan //定时器elemtype *_type // element type //元素类型sendx uint // send index //发送索引recvx uint // receive index //结束索引recvq waitq // list of recv waiters //接收等待队列-chsendq waitq // list of send waiters //发送等待队列ch-// lock protects all fields in hchan, as well as several// fields in sudogs blocked on this channel.//// Do not change another Gs status while holding this lock// (in particular, do not ready a G), as this can deadlock// with stack shrinking.lock mutex //锁保护hchan中的所有字段 }type waitq struct { //等待队列sudog双向链表结构first *sudog //(伪g)表示等待列表中的g例如在一个通道上用于发送/接收的glast *sudog //用acquireSudog分配releaseSudog释放从结构体上可以记住channel的一些特点比如说 (1)lock 锁操作channel是互斥的。先获取锁操作channel,释放锁 (2)elemtype类型创建的时候必须指定类型(大小可指定) ch : make(chan int,10) (3)waitq队列FIFO先进先出队列即通道能通过任意类型(unsafe.Pointer)的数据,(sudog)双向链表的g (4)dataqsiz通道容量有值有缓冲通道没值无缓冲通道 (5)qcount通道元素计数当前通道内的元素个数总数 (6)接受和发送通信有人发还要有人收意味必须2个g及以上的成员一起工作 (7)timer定时器定时可对channel做特殊操作 (8)closed关闭写(发送)已关闭通道会panic,读(接收)已关闭通道立刻返回true,false 二、channel创建 创建make(chan类型 元素类型缓冲容量大小),var chan类型 元素类型 func Test_2(t *testing.T) {ch1 : make(chan int) //双向ch11 : make(chan int, 10) //双向,带缓冲容量10ch2 : make(chan- int) //只写ch22 : make(chan int, 10) //只写,带缓冲容量10ch3 : make(-chan float64) //只读ch33 : make(chan int, 10) //只读,带缓冲容量10//go1.17_spec.html//chan T // can be used to send and receive values of type T//chan- float64 // can only be used to send float64s//-chan int // can only be used to receive intsvar ch4 chan int//通道是引用类型通道类型的空值是nil。g.Dump(ch1, ch11, ch2, ch22, ch3, ch33, ch4)//打印//chan int//chan int//chan- int//chan int//-chan float64//chan int//chan int }(1)channel通道类型 ChannelType ( chan | chan - | - chan )双向|单向发送(写)|单向接收(读) 只写操作读会报错。 使用场景上下文src/context/context.go的Context type Context interface { ...// a Done channel for cancellation.Done() -chan struct{} ...} 只读操作写会报错 使用场景上下文src/os/signal/signal.go的handlers var handlers struct {sync.Mutex// Map a channel to the signals that should be sent to it.m map[chan- os.Signal]*handler... }type stopping struct {c chan- os.Signalh *handler } (2)channel数据类型 任意如int,float64,bool,map... (3)缓冲容量 第二个参数给定数量,如10 无缓冲通道ch : make(chan int); 有缓冲通道ch : make(chan int,10) 三、向channel写数据 channel的发送要注意区分【有缓冲容量】和【无缓冲容量】 1.有人接收正常发送 func Test_send1(t *testing.T) {ch : make(chan int) //双向//开启goroutine将1~5的数发送到ch中go func() {for i : 1; i 5; i {fmt.Println(写入ch 元素, i)ch - i}close(ch) //写完关闭通道}()//在主goroutine中从ch中接收值打印for i : range ch {fmt.Println(读取ch 结果, i)}//写入ch 元素 1//写入ch 元素 2//读取ch 结果 1//读取ch 结果 2//写入ch 元素 3//写入ch 元素 4//读取ch 结果 3//读取ch 结果 4//写入ch 元素 5//读取ch 结果 5//主goroutine和goroutine读写互斥相互竞争锁。直到通道关闭主程结束 } 2.没人接收 看通道容量情况无缓存通道容量0一个都发不出,直接阻塞 注意select是非阻塞发送会直接返回 func Test_send2(t *testing.T) {ch : make(chan int) //双向//开启goroutine将1~5的数发送到ch中go func() {for i : 1; i 5; i {fmt.Println(写入ch 元素, i)ch - i}close(ch) //写完关闭通道}()//写入ch 元素 1//无缓存通道:没人接收尝试发送1时g被阻塞 } 思考为什么读要先于发尝试从源码角度分析因为无缓存channel的接收方会从发送方栈拷贝数据后发送方才会被放回调度队列种等待重新调度如果一直没有读发就一直卡住无法被唤醒 func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) { ... recv(c, sg, ep, func() { unlock(c.lock) }, 3) ... }//1.c通道 //2.发送方sg发送的值被放入通道中发送方被唤醒继续它的快乐之路 //3.接收方接收到的值(当前G)为写入ep func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {//无缓冲读if c.dataqsiz 0 {...if ep ! nil {// copy data from sender 接收是直接从发送的栈进行拷贝recvDirect(c.elemtype, sg, ep)}} else {//有缓冲读// 从缓存队列拷贝qp : chanbuf(c, c.recvx)...}gp.param unsafe.Pointer(sg)...//唤醒g准备执行goready(gp, skip1) }func recvDirect(t *_type, sg *sudog, dst unsafe.Pointer) {// dst is on our stack or the heap, src is on another stack.// The channel is locked, so src will not move during this// operation.src : sg.elemtypeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.Size_)//从from拷贝n个字节到to,from是src发送方,to就是dst接受方memmove(dst, src, t.Size_) } func memmove(to, from unsafe.Pointer, n uintptr) 有缓存通道容量5能先发5个第6个阻塞 func Test_send4(t *testing.T) {ch : make(chan int, 5) //双向//开启goroutine将1~5的数发送到ch中go func() {for i : 1; i 10; i {fmt.Println(写入ch 元素, i)ch - i}close(ch) //写完关闭通道}()//写入ch 元素 1//写入ch 元素 2//写入ch 元素 3//写入ch 元素 4//写入ch 元素 5//写入ch 元素 6//无缓存通道:没人接收前5个元素成功发送尝试发送6时g才被阻塞 } 3.发送到已关闭的通道会panic func Test_send3(t *testing.T) {ch : make(chan int) //双向close(ch) //关闭通道ch - 1//在主goroutine中从ch中接收值打印for i : range ch {fmt.Println(读取ch 结果, i)}//panic: send on closed channel }发送小结 1如果channel为nil如果非阻塞式发送(select send)直接返回false否则阻塞 2如果channel已关闭直接panic 3如果recevq等待队列有接收方直接拷贝数据给接收方并唤醒接收方的g 4如果channel缓冲区未满发到缓冲区否则阻塞”保护发送现场“等待被唤醒 四、向channel读数据 1.有人发送通道有值遍历通道如果通道未关闭读完元素后会报死锁的错误 func Test_read1(t *testing.T) {ch : make(chan int, 5) //双向for i : 1; i 5; i {fmt.Println(写入ch 元素, i)ch - i}close(ch)for i : 1; i 9; i {v, ok : -chfmt.Println(v, ok)}//写入ch 元素 1//写入ch 元素 2//写入ch 元素 3//写入ch 元素 4//写入ch 元素 5//1 true//2 true//3 true//4 true//5 true//fatal error: all goroutines are asleep - deadlock! } 2.没人发送 (1)make或var初始化之后就读取,不管有无容量都会一直阻塞,等待写入本次实验go版本(go1.20.5 ) 注意如果channel有值并且一直没关闭一直for循环读读完之后会报死锁的错误。 func Test_read2(t *testing.T) {ch : make(chan int) //双向for i : 1; i 9; i {v, ok : -chfmt.Println(v, ok)} } func Test_read3(t *testing.T) {ch : make(chan int, 5) //双向for i : 1; i 9; i {v, ok : -chfmt.Println(v, ok)} } func Test_read4(t *testing.T) {var ch chan intfor i : 1; i 9; i {v, ok : -chfmt.Println(v, ok)} } 3.读取已关闭的通道会不会panic 答案是不会panic,不影响 已关闭通道如果有值返回值,true 已关闭通道如果没值返回0,false func Test_read5(t *testing.T) {ch : make(chan int) //双向close(ch)for i : range ch {fmt.Println(读取ch 结果, i)}//0 false//0 false//0 false//0 false//0 false//0 false//0 false//0 false }func Test_read6(t *testing.T) {ch : make(chan int, 5) //双向for i : 1; i 5; i {fmt.Println(写入ch 元素, i)ch - i}close(ch)for i : 1; i 9; i {v, ok : -chfmt.Println(v, ok)}//写入ch 元素 1//写入ch 元素 2//写入ch 元素 3//写入ch 元素 4//写入ch 元素 5//1 true//2 true//3 true//4 true//5 true//0 false//0 false//0 false }4.for Range for ... range阻塞式读取channel的值直到channel被关闭 func Test_read(t *testing.T) {ch : make(chan int) //双向//开启goroutine将1~5的数发送到ch中go func() {for i : 1; i 5; i {fmt.Println(写入ch 元素, i)ch - i}close(ch) //写完关闭通道}()//在主goroutine中从ch中接收值打印for i : range ch {fmt.Println(读取ch 结果, i)}//写入ch 元素 1//写入ch 元素 2//读取ch 结果 1//读取ch 结果 2//写入ch 元素 3//写入ch 元素 4//读取ch 结果 3//读取ch 结果 4//写入ch 元素 5//读取ch 结果 5//主goroutine和goroutine读写互斥相互竞争锁。直到通道关闭主程结束 } 若close(ch)注释掉读完数据之后还继续读会报死锁的错误。 func Test_read(t *testing.T) {ch : make(chan int) //双向//开启goroutine将1~5的数发送到ch中go func() {for i : 1; i 5; i {fmt.Println(写入ch 元素, i)ch - i}//close(ch) //写完关闭通道}()//在主goroutine中从ch中接收值打印for i : range ch {fmt.Println(读取ch 结果, i)}//写入ch 元素 1//写入ch 元素 2//读取ch 结果 1//读取ch 结果 2//写入ch 元素 3//写入ch 元素 4//读取ch 结果 3//读取ch 结果 4//写入ch 元素 5//读取ch 结果 5//fatal error: all goroutines are asleep - deadlock! } 读取小结 1如果channel为nil如果非阻塞式接收(select receive)直接返回false,false否则阻塞 2如果channel计时器不为nil,检查计时,做超时处理 3如果channel上有可以接收的数据(empty函数)且是阻塞读blockfalse在channel未关闭时返回(false,false)如果未关闭再次检查empty函数,没可接收数据返回true,false 4当channel已关闭如果是无缓冲返回(0,false),如果有缓存执行recv()方法 从sendq队列或缓冲区中拷贝数据 5当channel未关闭有缓冲读缓冲数据如果非阻塞式接收(select receive)直接返回false,false 6当缓冲数据读完了”保护接收现场“等待被唤醒 五、channel死锁问题 1.同一个goroutine上执行 1.未初始化的channel,读死锁写死锁 func Test_deadlock1(t *testing.T) {// 未初始化的channel,直接写死锁var ch chan intch - 1 }func Test_deadlock2(t *testing.T) {// 未初始化的channel,直接写死锁var ch chan int-ch } 2.已初始化的channel 2.1无缓冲,直接读死锁写死锁 func Test_deadlock3(t *testing.T) {// 初始化无缓冲的channel,直接写死锁ch : make(chan int)ch - 1 }func Test_deadlock4(t *testing.T) {// 初始化无缓冲的channel,直接写死锁ch : make(chan int)val, ok : -chfmt.Println(val, ok) }2.2有缓冲 先写后读读完之后死锁 func Test_deadlock5(t *testing.T) {// 未初始化的channel,直接写死锁ch : make(chan int, 5)ch - 1ch - 2ch - 3for v : range ch {fmt.Println(v)}//1//2//3//fatal error: all goroutines are asleep - deadlock! } 先读后写死锁 func Test_deadlock6(t *testing.T) {// 未初始化的channel,直接写死锁ch : make(chan int, 5)for v : range ch {fmt.Println(v)}ch - 1ch - 2ch - 3//fatal error: all goroutines are asleep - deadlock! } 所以通信只是发生在1端容易造成死锁 2.不同的goroutine 五、关闭通道 关闭已关闭的通道会panic 六、 六、总结 1.通道创建类型有3种双向只读只写 2.通道有容量可设无缓冲通道和有缓冲通道 3.通道读写互斥 4.已关闭通道写panic,读有值再关闭panic 5.通道通常需要2个g一起工作
http://www.zqtcl.cn/news/444627/

相关文章:

  • 大型html5浅蓝色网站设计公司dede模板网店怎么开店详细教程
  • 一个阿里云怎么做两个网站吗樱花16q808a
  • 如何利用服务器做网站网站建设朝阳
  • 比邻店网站开发企查查企业信息查询在线
  • 家乡网站建设策划案专业建设专题网站
  • 网站建设公司挣钱吗wordpress评论内容密码保护
  • 上海专业建站最低价网站程序模板
  • 蚌埠网站建设哪家好创客贴官网
  • php网站建设参考文献wordpress 头像 很慢
  • 大连seo网站推广phpcmsv9手机网站源码
  • 公司做推广做网站好还是俄文网站引擎
  • 上海市建设咨询协会网站asp网站源码
  • 大家都在哪些网站上做医药招商wordpress po文件
  • 国外主题网站兰州app
  • 建设项目自主验收公示网站dedecms英文外贸网站企业模板下载
  • 做网站要服务器吗前端企业网站开发
  • 用html写一个个人介绍多网站怎么做seo
  • 做网站打广告犯法吗中国建设投资集团 网站首页
  • 怎么免费申请个人网站职业技能培训有哪些
  • 小型的企业网站湖南备案网站建设方案书
  • 现在做网站公司seo怎么做教程
  • asp化妆品网站windows优化大师有必要安装吗
  • 网站流量分析系统制作图片网站
  • 做网站技术路线广州番禺发布公众号
  • 企业网站自己可以做吗服装网站建设的利益分析
  • 网站做软件居众装饰集团有限公司
  • 南山网站制作联系电话芒果国际影城星沙店
  • 珠海网站设计费用建企业版网站多久
  • linux 网站搬家wordpress 卸载plugin
  • 江苏省建设厅网站 投诉编辑网站的软件手机