首页后端开发GO并发编程时遇到的问题(并发编程时遇到的问题有哪些)

并发编程时遇到的问题(并发编程时遇到的问题有哪些)

时间2023-03-24 17:32:02发布访客分类GO浏览484
导读:在完成一个需求时,我发现有个函数是这样写的:func test(names []string { for _, name := range names { doSomething(name } }观察逻辑发现这个数组中的每个元素...

在完成一个需求时,我发现有个函数是这样写的:

func test(names []string) {

	for _, name := range names {

		doSomething(name)
	}

}

观察逻辑发现这个数组中的每个元素执行起来,其实没有必然的先后关系,完全可以并发执行,于是我改了一版代码:

func test(names []string) {

	for _, name := range names {

		go func() {

			doSomething(name)
		}

	}

	time.Sleep(time.Second)
}

执行后令我疑惑的事情发生了,假设names="Zhao", "Qian", "Sun",那么执行的结果里只有"Sun"的记录。

由于当时刚接触Golang,想了半天也不知道为什么。但是后来我自己想明白了,for循环属于主goroutine,主goroutine才不会管其他goroutine是否被执行了。而我的goroutine是在循环结束的时候才执行的,这个时候的name就一定已经是"Sun"了。

比如这段代码,接近100%的概率什么都不会打印出来,这就是因为主goroutine只会自顾自的执行自己的工作,结束后则退出,那个时候一切都结束了:

fun main() {

	go fmt.Println("Hello")
}

接下来做了另外一版的修改,这样就很完美了:

func test(names []string) {

	for _, name := range names {

		go func(n string) {

			doSomething(n)
		}
(name)
	}

	time.Sleep(time.Second)
}
    

将name作为一个参数传入闭包中。此时函数内的name不会受到外部影响,这样就可以执行出正确的结果了。

这里有一点需要注意,由于name是string类型的,属于非引用类型,在当做参数被传入的时候,是会将其复制一份传入的,此时的入参就成了完全独立的存在,不受外部影响。

不过这个代码实现给我的感觉依旧很愚蠢,因为加上了一个sleep方法。如果有一个name的执行时间(或者调用接口网络抖动)超过了1s,当然主goroutine还是不会等它执行完成就会退出,会导致一些不可预见的问题发生。

总不可能无限制的增加sleep时长来换取安全性。实际上这些names是可以协同等待的,等待所有的goroutine执行结束之后,一起退出。这种模式有点类似于Java的CountDownLatch,在Golang中可以借助sync.WaitGroup来实现。

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!


若转载请注明出处: 并发编程时遇到的问题(并发编程时遇到的问题有哪些)
本文地址: https://pptw.com/jishu/298.html
JavaScript冷门知识(javascript) 微服务 - Go语言从单体服务到微服务(设计方案篇)

游客 回复需填写必要信息