繁体   English   中英

为什么goroutine没有身份

[英]Why does a goroutine have no identity

我是 golang 的新手,我正在阅读 gopl 书中的示例。

Go 编程语言书的第 9.8.4 节解释了为什么 Goroutine 没有程序员可以访问的身份概念

Goroutines 没有程序员可以访问的身份概念。 这是设计使然,因为线程本地存储往往被滥用。 例如,在使用具有线程本地存储的语言实现的 web 服务器中,许多函数通过查看该存储来查找有关 HTTP 请求的信息是很常见的。 但是,就像过度依赖全局变量的程序一样,这可能会导致不健康的“远距离操作”,其中 function 的行为不仅仅由其 arguments 决定,而是由它运行。 因此,如果线程的身份发生了变化——比如说,一些工作线程被征召来帮忙——function 就会神秘地出现异常行为。

并以 web 服务器为例来说明这一点。 但是,我很难理解为什么所谓的“远距离行动”是一种不好的做法,以及这如何导致

一个 function 不是由它的 arguments 单独决定的,而是由它运行的线程的身份决定的。

任何人都可以对此给出解释(最好是简短的代码片段)

任何帮助表示赞赏

假设我们有以下代码:

func doubler(num int) { 
    return num + num
}

doubler(5)将返回10 go doubler(5)也会返回10

如果需要,可以对某种线程本地存储执行相同的操作:

func doubler() { 
    return getThreadLocal("num") + getThreadLocal("num")
}

我们可以用以下方式运行它:

go func() {
    setThreadLocal("num", 10)
    doubler()
}()

但是哪个更清楚? 显式传递num参数的变量,还是“魔术地”从某种线程本地存储中获取变量的变量?

这就是“远距离行动”的含义。 setThreadLocal("num", 10) (距离较远)影响doubler()行为方式。


这个例子显然是人为的,但是相同的原理适用于更多真实的例子。 例如,在某些环境中,使用线程本地存储的东西(例如用户信息或其他“全局”变量)并不少见。

这就是您引用的段落将其与全局变量进行比较的原因:线程局部存储全局变量,仅适用于当前线程。

当您将参数作为参数传递时,定义起来会更加清晰。 在调试或编写测试时,无需考虑任何魔术(通常是未记录的)全局状态。

见我的回购

package main

import (
    "fmt"
    "time"

    "github.com/timandy/routine"
)

func main() {
    goid := routine.Goid()
    fmt.Printf("cur goid: %v\n", goid)
    go func() {
        goid := routine.Goid()
        fmt.Printf("sub goid: %v\n", goid)
    }()

    // Wait for the sub-coroutine to finish executing.
    time.Sleep(time.Second)
}

我建议在这篇文章中查看一个示例,该示例说明为什么有人可能想要获取有关函数正在运行的当前线程/线程的信息: stackoverflow-C#中的主线程

正如问题中指出的那样,在某些线程需求上(最有可能)对函数的行为进行调节会产生易调试的易碎/易错代码。

我想您的教科书想说的是,函数永远不要依赖于在特定线程中运行,查找线程等,因为这可能会导致意外行为(尤其是在API中,如果最终不明显的话,用户该功能必须在特定线程中运行)。 在Go中,仅通过语言设计就不可能做到这一点。 goroutine的行为绝不依赖于线程或类似的东西,仅仅是因为goroutine don't have an identity您正确说don't have an identity

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM