【问题标题】:Why does a goroutine have no identity为什么goroutine没有身份
【发布时间】:2018-07-10 21:03:21
【问题描述】:

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

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

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

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

一个函数不仅仅由它的参数决定,而是由它运行的线程的标识决定。

谁能解释一下(最好是短代码sn-ps)

感谢任何帮助!

【问题讨论】:

  • 正是这样:鉴于您没有任何其他方式来识别它 - 您必须通过参数明确地做到这一点。和往常一样 - 显式优于隐式。
  • 这是语言作者的设计决定。在设计语言甚至不允许这种使用的大型代码库中,线程标识很容易被误用。

标签: go goroutine


【解决方案1】:

假设我们有以下代码:

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

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

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

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

我们可以这样运行:

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

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

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


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

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

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

【讨论】:

    【解决方案2】:

    我建议查看这篇文章,了解为什么有人可能想要获取有关函数正在运行的当前线程/线程的信息的示例: stackoverflow - main threads in C#

    正如问题中所指出的,根据某些线程要求(很可能)调节函数的行为会产生难以调试的脆弱/容易出错的代码。

    我猜你的教科书想说的是,函数永远不应该依赖于在特定线程中运行、查找线程等,因为这可能会导致意外行为(尤其是在 API 中,如果不是很明显函数必须在特定线程中运行的最终用户)。在 Go 中,纯粹通过语言设计是不可能的。 goroutine 的行为永远不会仅仅因为 goroutines don't have an identity 正如你所说的那样依赖于线程或类似的东西。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-08-17
      • 1970-01-01
      • 2012-03-06
      • 1970-01-01
      • 2015-07-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多