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

比较好的网站建设出售外链

比较好的网站建设,出售外链,网站建设和Java,建一个网站需要多少时间表怎样才能让主goroutine等待其他goroutine? 上篇文章提到,一旦主 goroutine 中的代码执行完毕,当前的 Go 程序就会结束运行,无论其他的 goroutine 是否已经在运行了。那么,怎样才能做到等其他的 goroutine 运行完毕之后…

怎样才能让主goroutine等待其他goroutine?

上篇文章提到,一旦主 goroutine 中的代码执行完毕,当前的 Go 程序就会结束运行,无论其他的 goroutine 是否已经在运行了。那么,怎样才能做到等其他的 goroutine 运行完毕之后,再让主 goroutine 结束运行呢?

最简单粗暴的办法就是让主goroutine"小睡"一会儿。

for i := 0; i < 10; i++ {
go func() {fmt.Println(i)}()
}
time.Sleep(time.Millisecond * 500)

在for语句的后边,调用了time包的Sleep函数,并把time.Millisecond * 500的结果作为参数值传给了它。time.Sleep函数的功能就是让当前的 goroutine(在这里就是主 goroutine)暂停运行一段时间,直到到达指定的恢复运行时间。

time.Sleep函数会在被调用时用当前的绝对时间,再加上相对时间计算出在未来的恢复运行时间。显然,一旦到达恢复运行时间,当前的 goroutine 就会从“睡眠”中醒来,并开始继续执行后边的代码。

但是,让主 goroutine“睡眠”多长时间才是合适的呢? 如果“睡眠”太短,则很可能不足以让其他的 goroutine 运行完毕,而若“睡眠”太长则纯属浪费时间,这个时间就太难把握了。

我们可以创建一个通道,它的长度应该与我们手动启用的 goroutine的数量一致。在每个手动启用的 goroutine 即将运行完毕的时候,我们都要向该通道发送一个值。

package mainimport ("fmt"//"time"
)func main() {num := 10sign := make(chan struct{}, num)for i := 0; i < num; i++ {go func() {fmt.Println(i)sign <- struct{}{}}()}// 办法1。//time.Sleep(time.Millisecond * 500)// 办法2。for j := 0; j < num; j++ {<-sign}
}

声明通道sign的时候是以chan struct{}作为其类型的。其中的类型字面量struct{}有些类似于空接口类型interface{},它代表了既不包含任何字段也不拥有任何方法的空结构体类型。

注意,struct{}类型值的表示法只有一个,即:struct{}{}。并且,它占用的内存空间是0字节。确切地说,这个值在整个 Go 程序中永远都只会存在一份。虽然我们可以无数次地使用这个值字面量,但是用到的却都是同一个值。当我们仅仅把通道当作传递某种简单信号的介质的时候,用struct{}作为其元素类型是再好不过的了。

有没有比使用通道更好的方法?如果你知道标准库中的代码包sync的话,那么可能会想到sync.WaitGroup类型。没错,这是一个更好的答案。

怎样让我们启用的多个goroutine按照既定的顺序运行?

首先,我们需要稍微改造一下for语句中的那个go函数,要让它接受一个int类型的参数,并在调用它的时候把变量i的值传进去。为了不改动这个go函数中的其他代码,我们可以把它的这个参数也命名为i

for i := 0; i < 10; i++ {go func(i int) {fmt.Println(i)
}(i)
}

go语句被执行时,我们传给go函数的参数i会先被求值,如此就得到了当次迭代的序号。之后,无论go函数会在什么时候执行,这个参数值都不会变。也就是说,go函数中调用的fmt.Println函数打印的一定会是那个当次迭代的序号。

然后,我们再改造for语句中的go函数。

for i := uint32(0); i < 10; i++ {go func(i uint32) {fn := func() {fmt.Println(i)}trigger(i, fn)}(i)
}

go函数中先声明了一个匿名的函数,并把它赋给了变量fn。这个匿名函数做的事情很简单,只是调用fmt.Println函数以打印go函数的参数i的值。

在这之后,我调用了一个名叫trigger的函数,并把go函数的参数i和刚刚声明的变量fn作为参数传给了它。注意,for语句声明的局部变量igo函数的参数i的类型都变了,都由int变为了uint32

再来说trigger函数。该函数接受两个参数,一个是uint32类型的参数i, 另一个是func()类型的参数fn。你应该记得,func()代表的是既无参数声明也无结果声明的函数类型。

trigger := func(i uint32, fn func()) {for {if n := atomic.LoadUint32(&count); n == i {fn()atomic.AddUint32(&count, 1)break}time.Sleep(time.Nanosecond)}
}

trigger函数会不断地获取一个名叫count的变量的值,并判断该值是否与参数i的值相同。如果相同,那么就立即调用fn代表的函数,然后把count变量的值加1,最后显式地退出当前的循环。否则,我们就先让当前的 goroutine“睡眠”一个纳秒再进入下一个迭代。

注意,我操作变量count的时候使用的都是原子操作。这是由于trigger函数会被多个goroutine 并发地调用,所以它用到的非本地变量count,就被多个用户级线程共用了。因此,对它的操作就产生了竞态条件(race condition),破坏了程序的并发安全性。

所以,我们总是应该对这样的操作加以保护,在sync/atomic包中声明了很多用于原子操作的函数。

另外,由于选用的原子操作函数对被操作的数值的类型有约束,所以才对count以及相关的变量和参数的类型进行了统一的变更(由int变为了uint32)。

纵观count变量、trigger函数以及改造后的for语句和go函数,要做的是,让count变量成为一个信号,它的值总是下一个可以调用打印函数的go函数的序号。

这个序号其实就是启用 goroutine 时,那个当次迭代的序号。也正因为如此,go函数实际的执行顺序才会与go语句的执行顺序完全一致。此外,这里的trigger函数实现了一种自旋(spinning)。除非发现条件已满足,否则它会不断地进行检查。

最后要说的是,因为我依然想让主 goroutine 最后一个运行完毕,所以还需要加一行代码。

trigger(10, func(){})

调用trigger函数完全可以达到相同的效果。由于当所有手动启用的goroutine都运行完毕之后,count的值一定会是10,所以我就把10作为了第一个参数值。又由于我并不想打印这个10,所以我把一个什么都不做的函数作为了第二个参数值。

完整代码:

package mainimport ("fmt""sync/atomic""time"
)func main() {var count uint32trigger := func(i uint32, fn func()) {for {if n := atomic.LoadUint32(&count); n == i {fn()atomic.AddUint32(&count, 1)break}time.Sleep(time.Nanosecond)}}for i := uint32(0); i < 10; i++ {go func(i uint32) {fn := func() {fmt.Println(i)}trigger(i, fn)}(i)}trigger(10, func() {})
}

文章学习自郝林老师的《Go语言36讲》

http://www.zhtcad.com/news/189.html

相关文章:

  • 文字域名可以做网站上海网站快速优化排名
  • 浦项建设中国有限公司网站百度seo多少钱一个月
  • 安徽国贸网站建设网站登录入口
  • 郑州市哪里有网站建设地推app推广赚佣金
  • 网络广告营销的定义常州网站优化
  • 丰台深圳网站建设公司国内免费推广产品的网站
  • 可以做很多个网站然后哭推广内容营销策略
  • 青海省建设工程在哪个网站发布广告电话
  • 怎么推广网站厦门网站推广优化哪家好
  • 网站没有织梦后台网络市场营销策划书
  • 做卡盟开端网站要多少钱百度上海分公司
  • 邢路桥建设总公司网站网络推广外包公司哪家好
  • 奥美广告公司排名定西seo排名
  • 做外贸有哪些好的网站有哪些百度关键词优化有效果吗
  • h5网站不利于优化吗2022真实新闻作文400字
  • 微商城网站开发视频怎么去做推广
  • app软件大全下载免费seo公司
  • 上百度推广 免费做网站信息流优化师招聘
  • 在家做的手工活哪里有网站做运营需要具备什么能力
  • 什么样的网站必须做备案互动营销的案例及分析
  • 做创意美食的视频网站网络营销方案模板
  • html网站开发软件全网营销是什么意思
  • 济南建设网站的公司吗宁波网站推广方式怎么样
  • 做网站推广怎么样美食软文300字
  • 学院门户网站建设必要性售卖链接
  • 控制面板网站什么平台可以免费打广告
  • 做黄色网站网站会被抓吗宁波seo网络推广主要作用
  • 北京全网推广键词优化排名
  • 个人网页设计论文的开题报告优化大师是什么意思
  • wordpress 首页添加图片保定seo排名