解决golang sync.Wait()不执行的问题

goroutine 似乎不用解释太多,可以利用它实现多线程,也可以利用它来实现异步事件。

在使用关键字go的过程中,常常会将用到sync.WaitGroup,如下一段代码。

package main
import (
	"fmt"
	"sync"
	"time"
)
func Run() {
	var wg = &sync.WaitGroup{}
	go func() {
		wg.Add(1)
		fmt.Println("halo world start")
		time.Sleep(time.Second * 5)
		fmt.Println("halo world end")
		wg.Done()
	}()
	// time.Sleep(time.Millisecond * 5)
	// fmt.Println("server will start")
	wg.Wait()
}
func main() {
	Run()
}
// output:
//

期待的结果是打印 halo world start,5秒后打印halo world end,但是结果就是什么都没有,并且进程立即就结束了。

原因

关键字go是异步的,当执行到go,不会立即执行go 后面的内容,而且继续往下执行。此时wg.Add(1)还没有来得及执行,wg.Wait()就已经执行,即不会发生等待,进程就结束了。

怎么解决:

只需要在wg.Wait()前有其他操作,给与足够的时间让wg.Add(1)执行即可,

方法一、时间等待,在wg.Wait()前加一句time.Sleep(time.Millisecond*5),既不影响性能,也能让wg.Add(1)来得及执行

方法二、有IO操作,在wg.Wait()有其他IO操作,比如fmt.Println("server will start"),原因是std的输出会将进程从用户态转向内核态,打印命令发出后,又切回用户态,这个状态的转换是很有消耗的,wg.Add(1)也就有时间执行。

Don't worry

是否有存在担心,方法一的时间等待,等待的时候不够长,还是让wg.Add(1)来不及执行。don't worry.

这里涉及到goroutine的调度问题,go进程在执行过程中,必须从goroutine队列中取出一个来执行,当wg.Wait()执行前就算执行time.Sleep(time.Nanosecond), 一纳秒,一…一…一纳秒,wg.Add(1)也来得及执行,因为主goroutine会被切换到睡眠状态,go进程必须要取一个线程来执行,就会取到wg.Add(1)这个线程,接下来就顺理成章了。

同时方法二也是异曲同工,当发出打印的事件,整个进程都会被切换到就绪态,然后再被cpu执行。

补充:【golang】sync.WaitGroup{}的wait()调用位置不同导致意想不到错误

协程go多了,总觉的天下我有,没事就喜欢go一个协程,信手拈来,在项目中写个如下类似代码:

  wh := sync.WaitGroup{}
  out := make(chan string)
  go func() {
    wh.Wait()
    close(out)
  }()
  go func() {
    for i := 0; i < 2; i++ {
      wh.Add(1)
      go tt(out)
      wh.Done()
    }
  }()

想着开个协程去wait所有协程组,测试一下通了,没问题,好牛逼,协程呀!!

可多测试即便就会出现:

send close channel

或者协程定死在某一个,还自已为是的认为自己写的子方法估计不小心关闭了channel,找了半天只找到在wg.wait()后进行了关闭。就这样扣了好久,还没想到自己画蛇添足的错误,经大佬一指点,原来开一个协程,还没等后一个协程进行wg.add(1)操作,wg.wait()就已经过了,关闭了channel。

只好老老实实写:

  wh := sync.WaitGroup{}
  out := make(chan string)
  go func() {
    for i := 0; i < 2; i++ {
      wh.Add(1)
      go tt(out)
      wh.Done()
    }
    wh.Wait()
    close(out)
  }()

其实就是一个小小的同步问题,旁观者清呀!!!

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • 快速解决Golang Map 并发读写安全的问题

    一.错误案例 package main import ( "fmt" "time" ) var TestMap map[string]string func init() { TestMap = make(map[string]string, 1) } func main() { for i := 0; i < 1000; i++ { go Write("aaa") go Read("aaa") go Write(&qu

  • golang执行命令操作 exec.Command

    我就废话不多说了,大家还是直接看代码吧~ cmd := exec.Command("cmd") in := bytes.NewBuffer(nil) cmd.Stdin = in//绑定输入 var out bytes.Buffer cmd.Stdout = &out //绑定输出 go func() { in.WriteString("node E:/design/test.js\n")//写入你的命令,可以有多行,"\n"表示回车 }

  • golang中sync.Map并发创建、读取问题实战记录

    背景: 我们有一个用go做的项目,其中用到了zmq4进行通信,一个简单的rpc过程,早期远端是使用一个map去做ip和具体socket的映射. 问题 大概是这样 struct SocketMap { sync.Mutex sockets map[string]*zmq4.Socket } 然后调用的时候的代码大概就是这样的: func (pushList *SocketMap) push(ip string, data []byte) { pushList.Lock() defer pushLi

  • 解决Golang map range遍历结果不稳定问题

    闲言少叙,本文主要是想介绍一个Golang开发常见的一个问题.然而,此问题对于初学者来说却经常容易陷入坑中. 问题 我在写一段代码时,使用了Golang的map数据结构,目的是想用map缓存计数结果.简单来说map的键也是整型的,且以递增顺序存储.我的最初想法是,在统计结束后,按照map中存储的键有序输出值.可是,当我运行程序时,结果并不是我想要的,而且有一定概率运行结果不同. 问题代码 func sortByBits(arr []int) []int { var bitmap = make(m

  • 浅谈golang类型断言,失败类型断言返回值问题

    失败的类型断言,返回的值为最近断言类型的零值 代码入下: func main() { var data interface{} = "ehoo" if res, ok := data.(int); ok { fmt.Printf("int res:%d\n", res) } else if res, ok := data.(bool); ok { fmt.Printf("bool res:%b\n", res) } else { fmt.Prin

  • golang等待触发事件的实例

    我就废话不多说了,大家还是直接看代码吧~ type Wait interface { // Register waits returns a chan that waits on the given ID. // The chan will be triggered when Trigger is called with // the same ID. Register(id uint64) <-chan interface{} // Trigger triggers the waiting c

  • 解决golang sync.Wait()不执行的问题

    goroutine 似乎不用解释太多,可以利用它实现多线程,也可以利用它来实现异步事件. 在使用关键字go的过程中,常常会将用到sync.WaitGroup,如下一段代码. package main import ( "fmt" "sync" "time" ) func Run() { var wg = &sync.WaitGroup{} go func() { wg.Add(1) fmt.Println("halo world

  • 一文解析 Golang sync.Once 用法及原理

    目录 前言 1. 定位 2. 对外接口 3. 实战用法 3.1 初始化 3.2 单例模式 3.3 关闭channel 4. 原理 5. 避坑 前言 在此前一篇文章中我们了解了 Golang Mutex 原理解析,今天来看一个官方给出的 Mutex 应用场景:sync.Once. 1. 定位 Once is an object that will perform exactly one action. sync.Once 是 Go 标准库提供的使函数只执行一次的实现,常应用于单例模式,例如初始化配

  • Golang源码分析之golang/sync之singleflight

    目录 1.背景 1.1. 项目介绍 1.2.使用方法 2.源码分析 2.1.项目结构 2.2.数据结构 2.3.API代码流程 3.总结 1.背景 1.1. 项目介绍 golang/sync库拓展了官方自带的sync库,提供了errgroup.semaphore.singleflight及syncmap四个包,本次分析singlefliht的源代码.singlefliht用于解决单机协程并发调用下的重复调用问题,常与缓存一起使用,避免缓存击穿. 1.2.使用方法 go get -u golang

  • Golang控制协程执行顺序方法详解

    目录 循环控制 通道控制 互斥锁 async.Mutex 在 Go 里面的协程执行实际上默认是没有严格的先后顺序的.由于 Go 语言 GPM 模型的设计理念,真正执行实际工作的实际上是 GPM 中的 M(machine) 执行器,而我们的协程任务 G(goroutine) 协程需要被 P(produce) 关联到某个 M 上才能被执行.而每一个 P 都有一个私有队列,除此之外所有的 P 还共用一个公共队列.因此当我们创建了一个协程之后,并不是立即执行,而是进入队列等待被分配,且不同队列之间没有顺

  • 解决pycharm下os.system执行命令返回有中文乱码的问题

    如下所示: source = ['C:\\Users\\admin\\Desktop\\pythonLearning'] target_dir = 'C:\\Users\\admin\\Desktop' print(time.strftime('%Y%m%d%H%M%S')) target = target_dir + os.sep + time.strftime('%Y%m%d%H%M%S') + '.zip' if not os.path.exists(target_dir): os.mkd

  • 解决$store.getters调用不执行的问题

    api:https://vuex.vuejs.org/zh/guide/getters.html 场景: 在登录时将登录得到的用户信息存储在vuex的state和sessionStorage中.使用时在state中获取,当因为刷新等原因导致state中没有数据时,去sissionStorage中获取. 错误: 登录后,需要获取用户信息时,getters中属性的方法不会执行.只是去getters中获取缓存 解决方法: 将getters中的属性改写成方法,这样每次调用的时候就会执行,去从新获取数据.

  • 解决安装pycharm后不能执行python脚本的问题

    其中一种原因:pycharm没有设置系统解析器 解决方法 打开pycharm->File->Settings->Project Interpreter->设置python路径(系统python) 以上这篇解决安装pycharm后不能执行python脚本的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • 解决JQuery的ajax函数执行失败alert函数弹框一闪而过问题

    先查看<form>标签是否有action属性,如果没有,并且最后<button>标签的type属性为'submit'时,默认提交位置就是当前页面 如果在页面右键检查,点击网络,会在开头发现这样的post包: 在右侧消息头处可见,请求网址为当前网址,并且响应头部类型为html 所以只要把form表单里最后提交按钮的type="submit"换为type="button",把按钮变成原生按钮, 就可以正确使用ajax方法传递数据,原因就是form

  • 解决Python paramiko 模块远程执行ssh 命令 nohup 不生效的问题

    Python - paramiko 模块远程执行ssh 命令 nohup 不生效的问题解决 1.使用 paramiko 模块ssh 登陆到 linux 执行nohup命令不生效 # 执行命令 def command(ssh_config, cmd, result_print=None, nohup=False): ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.con

  • 解决PyCharm IDE环境下,执行unittest不生成测试报告的问题

    问题:在利用unittest框架生成测试报告时,代码执行完成,没有在指定目录下生成报告 原因:PyCharm会默认使用自带的unittest框架来执行单元测试,不会执行main函数中的代码,所以不生成测试报告 解决方法: 1.点击PyCharm右上角的 Uittest in xxx.py下拉框 2.点击Edit Configuration...,在弹出的对话框中,删除 unittests in xxxx.py 3.点击绿色"+"号,新增Python文件 4.Script Path 路径

随机推荐