我是golang的新手,正在阅读gopl书中的示例。
Go编程语言书籍的9.8.4节解释了为什么Goroutines没有程序员可以访问的身份概念
Goroutine没有程序员可以访问的身份概念。这是设计使然,因为线程本地存储会被滥用。例如,在以具有线程本地存储的语言实现的Web服务器中,许多功能通常都会通过查看该存储来查找有关HTTP请求的信息,这些信息当前正以其名义工作。但是,就像过度依赖全局变量的程序一样,这可能导致不健康的“远距离操作”,在这种情况下,函数的行为不仅取决于其参数,还取决于线程中的身份。它运行。因此,如果线程的身份应更改(例如,要求某些工作线程帮助),则该函数会神秘地发生行为。
,并使用Web服务器的示例来说明这一点。但是,我很难理解为什么所谓的“远距离行动”是一种不好的做法,以及它如何导致
一个函数不是仅由其参数确定,而是由其运行的线程的标识确定。
任何人都可以对此进行解释(最好是简短的代码片段)
感谢您的帮助!
答案 0 :(得分:2)
假设我们有以下代码:
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()
的行为。
这个例子显然是人为的,但是相同的原理适用于更多真实的例子。例如,在某些环境中,使用线程本地存储的东西(例如用户信息或其他“全局”变量)并不少见。
这就是为什么您引用的段落将其与全局变量进行比较的原因:线程本地存储是全局变量,仅适用于当前线程。
当您将参数作为参数传递时,定义起来会更加清晰。调试事物或编写测试时,无需考虑任何魔术(通常是未记录的)全局状态。
答案 1 :(得分:0)
我建议看一下这篇博文,以了解为什么有人可能想获取有关当前正在运行的函数的线程的信息的示例: stackoverflow - main threads in C#
如问题中所指出的那样,在某种特定的线程需求下(最有可能)对函数的行为进行调节会产生易调试的易碎/易错代码。
我想您的教科书想说的是,一个函数永远不要依赖于在特定线程中运行,查找线程等,因为这可能会导致意外行为(尤其是在API中,如果不明显)最终用户该功能必须在特定线程中运行)。在Go中,仅通过语言设计就不可能做到这一点。 goroutine的行为绝不依赖于线程或类似的东西,仅仅是因为您正确地说过goroutines r/1/posts/
。