您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

golang并发不是并行

2024/3/15 14:35:16发布23次查看
并发不等于并行
golang的核心开发人员rob pike专门提到了这个话题                         (推荐学习:go)
虽然我们在for循环中使用了go 创建了一个goroutine,我们想当然会认为,每次循环变量时,golang一定会执行这个goroutine,然后输出当时的变量。 
这时,我们就陷入了思维定势。 默认并发等于并行。
诚然,通过go创建的goroutine是会并发的执行其中的函数代码。
 但一定会按照我们所设想的那样每次循环时执行吗?
 答案是否定的!
rob pike专门提到了golang中并发指的是代码结构中的某些函数逻辑上可以同时运行,但物理上未必会同时运行。而并行则指的就是在物理层面也就是使用了不同cpu在执行不同或者相同的任务。
golang的goroutine调度模型决定了,每个goroutine是运行在虚拟cpu中的(也就是我们通过runtime.gomaxprocs(1)所设定的虚拟cpu个数)。
 虚拟cpu个数未必会和实际cpu个数相吻合。每个goroutine都会被一个特定的p(虚拟cpu)选定维护,而m(物理计算资源)每次回挑选一个有效p,然后执行p中的goroutine。
每个p会将自己所维护的goroutine放到一个g队列中,其中就包括了goroutine堆栈信息,是否可执行信息等等。默认情况下,p的数量与实际物理cpu的数量相等。
因此当我们通过循环来创建goroutine时,每个goroutine会被分配到不同的p队列中。而m的数量又不是唯一的,当m随机挑选p时,也就等同随机挑选了goroutine。
在本题中,我们设定了p=1。所以所有的goroutine会被绑定到同一个p中。 如果我们修改runtime.gomaxprocs的值,就会看到另外的顺序。 如果我们输出goroutine id,就可以看到随机挑选的效果:
func main() {wg := sync.waitgroup{}wg.add(20)for i := 0; i < 10; i++ {go func() {var buf [64]byten := runtime.stack(buf[:], false)idfield := strings.fields(strings.trimprefix(string(buf[:n]), "goroutine "))[0]id, err := strconv.atoi(idfield)if err != nil {panic(fmt.sprintf("cannot get goroutine id: %v", err))}fmt.println("go routine 1 i: ", i, id)wg.done()}()}for i := 0; i < 10; i++ {go func(i int) {var buf [64]byten := runtime.stack(buf[:], false)idfield := strings.fields(strings.trimprefix(string(buf[:n]), "goroutine "))[0]id, err := strconv.atoi(idfield)if err != nil {panic(fmt.sprintf("cannot get goroutine id: %v", err))}fmt.println("go routine 2 i: ", i, id)wg.done()}(i)}wg.wait()}
输出如下:
go routine 2 i: 9 24go routine 1 i: 10 11go routine 1 i: 10 5go routine 1 i: 10 6go routine 2 i: 3 18go routine 1 i: 10 9go routine 1 i: 10 10go routine 1 i: 10 8go routine 2 i: 0 15go routine 2 i: 4 19go routine 2 i: 6 21go routine 1 i: 10 7go routine 1 i: 10 14go routine 2 i: 7 22go routine 2 i: 8 23go routine 1 i: 10 13go routine 2 i: 5 20go routine 1 i: 10 12go routine 2 i: 1 16go routine 2 i: 2 17⋊> ~/s/g/g/s/t/c/goroutine ./goroutinego routine 1 i: 10 11go routine 2 i: 9 24go routine 1 i: 10 6go routine 1 i: 10 14go routine 1 i: 10 9go routine 1 i: 10 10go routine 1 i: 10 12go routine 2 i: 0 15go routine 1 i: 10 13go routine 1 i: 10 5go routine 2 i: 1 16go routine 2 i: 5 20go routine 1 i: 10 7go routine 2 i: 7 22go routine 2 i: 3 18go routine 2 i: 2 17go routine 2 i: 4 19go routine 1 i: 10 8go routine 2 i: 8 23go routine 2 i: 6 21
我们再回到这道题中,虽然在循环中通过go定义了一个goroutine。但我们说到了,并发不等于并行。因此虽然定义了,但此刻不见得就会去执行。
需要等待m选择p之后,才能去执行goroutine。 关于golang中goroutine是如何进行调度的(gpm模型),可以参考scalable go scheduler design doc或者learnconcurrency
以上就是golang并发不是并行的详细内容。
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product