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

做seo网站地图重要吗网站网址怎么写

做seo网站地图重要吗,网站网址怎么写,ps网站如何做烫金的文字,域名的注册方式目录 引言一、sync.WaitGroup二、channel创建channle操作缓冲多返回值模式单向通道 引言 在不做修饰的程序中,代码是串行执行的 串行、并发与并行串行:事物按照一定的发展顺序并发:同一时间段执行多个任务(一边吃饭一边看电视&am…

目录

  • 引言
  • 一、sync.WaitGroup
  • 二、channel
    • 创建
    • channle操作
    • 缓冲
    • 多返回值模式
    • 单向通道

引言

在不做修饰的程序中,代码是串行执行的

   串行、并发与并行串行:事物按照一定的发展顺序并发:同一时间段执行多个任务(一边吃饭一边看电视)并行:同一时刻执行多个任务(你和你的好朋友都在学习go语言)

对于这样一段代码

func hello() {fmt.Println("hello")
}
func main() {hello()fmt.Println("world")
}

输出

hello
world

如果启动一个goroutine

func hello() {fmt.Println("hello")
}
func main() {go hello()fmt.Println("world")
}

输出

world

为什么会出现这样的结果
这是因为在创建goroutine时需要花费一定时间,在这段时间内,main goroutine是继续执行的,如果main goroutine执行完成,就不会管其他的goroutine,程序直接退出,所以不会打印出hello

如果想要“hello”也打印出来,就要想办法让main goroutine 等一等

最简单粗暴的方法就是调用time.Sleep函数,延迟结束程序

func hello() {fmt.Println("hello")
}
func main() {hello()fmt.Println("world")time.Sleep(time.Second)
}

编译执行后打印

world
hello

为什么先打印world?
同样的,创建goroutine时需要花费一定时间,在这段时间内,main goroutine继续执行,理解为因为创建goroutine时花费了时间,所以goroutine执行起来比main goroutine慢

但是使用这种方法存在一定的问题,因为不知道程序执行具体需要多长时间
如果sleep时间过长,可能会存在 一段时间内,程序没有执行任务 的情况,这样就降低了效率
如果sleep时间过短,还是有可能打印不出goroutine中的语句


要更好的解决这个问题,有三种方法可以使用

  1. sync.WaitGroup
  2. channel
  3. Context

先不说第三种,因为还不会


一、sync.WaitGroup

使用sync.WaitGroup优化上面程序的代码是

var wg sync.WaitGroup //声明等待组变量func hello() {fmt.Println("hello")wg.Done() //当前goroutine执行完毕
}func main() {wg.Add(1) //记录需要等待的goroutine数量go hello()fmt.Println("world")wg.Wait() // 等待直到所有goroutine执行完成
}

编译执行后打印

world
hello
  • sync.WaitGroup定义
type WaitGroup struct {noCopy noCopystate atomic.Uint64 // high 32 bits are counter, low 32 bits are waiter count.sema  uint32
}

不难而见,WaitGroup是一个结构体
sync包中提供了三种WaitGroup的方法

方法名功能
func (wg *WaitGroup) Add(delta int)记录要等待的协程的数量
func (wg *WaitGroup) Done()记录当前协程已执行完毕
func (wg *WaitGroup) Wait()等待子协程结束,否则阻塞

sync.WaitGroup内部可以理解为一个计数器,计数器的值可以增加和减少。
例如当我们启动了 N 个并发任务时,就将计数器值增加N;
每个任务完成时通过调用 Done 方法将计数器减1;
通过调用 Wait 来等待并发任务执行完,当计数器值为 0 时,表示所有并发任务已经完成

举一个通俗的例子,这里将计数器称为count
你室友喊你去打游戏,你给自己定了两个目标:复习二重积分和三重积分,完成这两个目标就去和室友打游戏
首先,你给自己定了两个目标(count = 2),复习完二重积分后,你还剩下一个目标没有完成(count = 1),这时候你的室友还要继续等你(wait),好了,又把三重积分复习完了(count = 0),这时候你就和室友去打游戏了

WaitGroup 通常适用于可动态调整协程数量的时候,例如事先知道协程的数量,又或者在运行过程中需要动态调整。

WaitGroup是结构体,作为函数参数传参时,应该传递指针而不是值;如果传递值,只是将WaitGroup拷贝后,对拷贝的WaitGroup进行修改,不会改变真正的WaitGroup的值,这可能会导致主协程一直阻塞等待,程序将无法正常运行


二、channel

这一部分是我在学习channel 时候的笔记加上自己的理解
参考🔗李文周的博客-Go语言基础之并发 🔗Golang 中文学习文档-并发

创建

  1. 声明
var 变量名称 chan 元素类型
chan:关键字
元素类型:是指通道中传递元素的类型
	var ch chan int //传递整型的通道var ch1 chan string  //传递string类型的通道

没有初始化之前通道是对应类型的零值

  1. 创建

用make创建

	ch1 := make(chan int)      //没有缓冲区(下面说缓冲)ch2 := make(chan int, 1)  //缓冲区为1
  1. 关闭

使用内置的 close 关闭通道

close定义:

func close(c chan<- Type)

关闭ch通道:

close(ch)

用户必须发出一个关闭通道的指令,通道才会关闭
与文件操作不同,文件在结束操作后必须关闭,但是通道不必须关闭


channle操作

通道的操作有 发送(send)、接收(receive)和关闭(close)。
发送和接收都用符号 ‘<-’

  1. 发送

ch <-:表示对一个通道写入数据

ch <- 5 // 把5发送到ch中
  1. 接收

<- ch:表示对一个通道读取数据(直接看箭头指向区分这两种操作就可以)

  • 单返回值
x := <- ch // 从ch中接收值并赋值给变量x
<-ch       // 从ch中接收值,忽略结果
  • 双返回值
value, ok := <-ch

value:通道中的值,如果被关闭返回对应的零值
ok:布尔类型的值,通道关闭时返回false,否则返回true

双返回值还可以用来判断通道是否关闭

  • 判断通道是否被关闭:
    示例:value, ok := <-ch
    value:从通道中取出的值,如果通道被关闭则返回对应类型的零值
    ok:通道ch关闭时返回false,否则返回true

  • for range 接收值
    通常用for range循环从通道中接收值
    如果通道被关闭,会 在通道内的所有制被接收完毕后 自动退出循环
    如果没有关闭,使用for range执行时会出错

	ch4 := make(chan int, 4)ch4 <- 1ch4 <- 2ch4 <- 3ch4 <- 4close(ch4)for value := range ch4 {fmt.Println(value)}}func recv(c chan int) {ret := <-cfmt.Println("接收成功", ret)
}

输出

1
2
3
4

通道的发送接收操作可以理解为一个容器
如果容器有空间,就可以把物品放进容器;
如果容器空间满了,在容器中取出物品后,容器空间又有剩余,又可以把其他物品放入容器


关闭后的通道有以下特点:

  1. 对一个关闭的通道再发送值就会导致panic
  2. 对一个关闭的通道继续接收会一直获取值直到通道为空
  3. 对一个关闭的并且没有值的通道执行接收操作会得到对应类型的零值
  4. 关闭一个已经关闭的通道会导致panic
  5. 对已经关闭的通道再执行close也会引发panic

缓冲

  • 无缓冲的通道(阻塞的通道)
	ch1 := make(chan int)  //ch1是一个无缓冲的通道ch1 <- 10fmt.Println("发送成功")

go fatal error: all goroutines are asleep - deadlock!

deadlock -- 表示程序中的goroutine都被挂起导致程序死锁了对一个无缓冲区通道执行发送操作,会发生阻塞对一个无缓冲通道执行接收操作,没有任何向通道中发送值的操作也会导致接受操作阻塞

应对阻塞通道的方法

  1. 创建goroutine
    func recv(c chan int) {ret := <-cfmt.Println("接收成功", ret)}func main(){ch2 := make(chan int)go recv(ch2)ch2 <- 10 // 发送操作fmt.Println("发送成功")close(ch2)//fmt.Println(<-ch2) -- 报错了}
这段代码的过程
case1:如果先进行发送操作,发生堵塞,直到另一个goroutine执行接收操作
case2:如果先进行接收操作,发生堵塞,直到另一个goroutine执行发送操作
  1. 使用有缓冲的通道
	ch3 := make(chan int, 1)ch3 <- 1fmt.Println("发送成功 ")x1 := <-ch3fmt.Println(x1)  //输出1ch3 <- 2close(ch3)//对关闭的通道执行接收操作,会直到取完通道中的元素num0 := len(ch3)  //len--获取通道中元素个数x2 := <-ch3num := len(ch3)fmt.Println(num0, x2, num) //输出 1 2 0
只要通道的容量大于0,那就是有缓冲的通道,通道的容量表示通道中最大能存放的元素数量。
当通道内一铀元素达到最大容量后,再向通道中执行发送操作就会阻塞(如果接收后再发送就不会了,相当于清空了)
len -- 获取通道内元素的数量
cap -- 获取通道的容量

多返回值模式

  • 判断通道是否被关闭:
    示例:value, ok := <-ch
    value:从通道中取出的值,如果通道被关闭则返回对应类型的零值
    ok:通道ch关闭时返回false,否则返回true

  • for range 接收值
    通常用for range循环从通道中接收值
    如果通道被关闭,会 在通道内的所有制被接收完毕后 自动退出循环
    如果没有关闭,使用for range执行时会出错

	ch4 := make(chan int, 4)ch4 <- 1ch4 <- 2ch4 <- 3ch4 <- 4close(ch4)for value := range ch4 {fmt.Println(value)}}func recv(c chan int) {ret := <-cfmt.Println("接收成功", ret)
}

输出

1
2
3
4

单向通道

现在有两个函数
producer 函数 返回通道,并且执行发送操作
consume r函数从通道中接收值进行计算

func Producer() chan int {ch := make(chan int) //有没有缓冲值都可以//创建一个新的goroutine执行发送数据的任务go func() {for i := 0; i < 5; i++ {ch<-i}}close(ch)}()return ch
}func Consumer(ch chan int) int {sum := 0for value := range ch {sum += value}return sum
}

上面的代码没办法阻止在接收通道中执行发送操作,同理,没办法阻止在发送通道中执行接收操作
可以 限制参数或者返回值 来限制函数

<-chan int //只接收通道,只能接收不能发送
chan <-int //只发送通道,只能发送不能接收

改写成

func Producer1() <-chan int { //发送操作ch := make(chan int) //有没有缓冲值都可以//创建一个新的goroutine执行发送数据的任务go func() {for i := 0; i < 10; i++ {//有 1 3 5 7 9if i%2 == 1 {ch <- i}}close(ch)}()return ch
}func Consumer1(ch <-chan int) int { //接收操作sum := 0for value := range ch {sum += value}return sum
}func main() {//在函数传参及任何赋值操作中全向通道(正常通道)可以转换为单向通道,但是没办法反向转换(单项通道没办法转换成全向通道)ch1 := make(chan int, 1)ch1 <- 10close(ch1)Consumer1(ch1) //在传参时将ch1转为单项通道ch2 := make(chan int, 1)ch2 <- 4           //向ch2中发送4var ch3 <-chan int //声明一个通道 只接收ch3 = ch2          //变量赋值时将ch2转换为单向通道<-ch3              //接收操作
}

文章转载自:

http://WxdnMATT.xnymt.cn
http://NEMXzYLa.xnymt.cn
http://740S6Fhg.xnymt.cn
http://Y209lRA7.xnymt.cn
http://RQLotDUH.xnymt.cn
http://peHqfyWp.xnymt.cn
http://MPw8ihnU.xnymt.cn
http://2appqDGc.xnymt.cn
http://SOpQVLpI.xnymt.cn
http://aNB9gr9J.xnymt.cn
http://BImJbLHq.xnymt.cn
http://O6aIZrxl.xnymt.cn
http://yBvNxIVO.xnymt.cn
http://Nkx1VzrU.xnymt.cn
http://LtG4i2qF.xnymt.cn
http://RTyh0dt8.xnymt.cn
http://wHyJ9UPV.xnymt.cn
http://TvntQBRr.xnymt.cn
http://ABTV9iJ7.xnymt.cn
http://kXccwbuu.xnymt.cn
http://1EIvSggu.xnymt.cn
http://52hlbZZj.xnymt.cn
http://HnQIcaZE.xnymt.cn
http://mv61lvib.xnymt.cn
http://cupv2V6f.xnymt.cn
http://MxRmVVUV.xnymt.cn
http://VgnARlyR.xnymt.cn
http://vJiNWu7G.xnymt.cn
http://agYBqwDl.xnymt.cn
http://5GIwGy1k.xnymt.cn
http://www.dtcms.com/wzjs/686082.html

相关文章:

  • 广州正规网站建设公司动画制作视频
  • 网站运营团队各岗位的职责是什么大连做企业网站排名
  • 昆明网站快速优化排名苏州官网设计
  • 网站框架类型网站排名大全
  • 做的比较炫的网站社交和门户网站的区别
  • 沈阳网站建设多少钱销售类网站开发
  • 新公司做网站怎么做查询网站备案密码
  • 定做网站多少钱网页制作公司北京
  • 做卡盟网站教程客户管理软件免费版哪个好用
  • 信息管理系统网站开发教程做网站有什么作用
  • 网站建设 上海网站永久免费网站怎么建
  • 郑州做网站的公司排名珠海十大网站建设公司哪家好
  • 大企业网站样式企业网站 自助建站
  • 企业网站建站模板深圳市建筑人才网
  • 网站模板如何修改域名今天的国际新闻最新消息
  • 沈阳餐饮网站建设怎么申请域名建网站
  • 微信网站建设 知乎外链建设的方式有哪些
  • dedecms做的网站云南网站建设的价值
  • 合肥本地网站工商信息查询官网
  • 邢台专业做网站关键词推广效果分析
  • 淘客推广网站怎么做的想学做网站seo 在哪学 电话多少
  • 群晖可以做网站服务器广州网业有限公司
  • 加强网站集约化建设福州seo博客
  • 专业网站定制 北京商标设计创意
  • 做网站是否需要自购服务器设计制作植物标识牌
  • 企业网站建设联系电话门户网站区别
  • 网站模板下载带后台如何注册公司多少钱
  • 响应式网站用什么开发的wordpress小工具失效
  • 现在都用什么软件做网站开发软件的网站
  • 许昌建网站的公司在哪条路威海企业做网站