【问题标题】:Go lang global variables without goroutines overwriting没有 goroutines 覆盖的 Go lang 全局变量
【发布时间】:2017-07-28 19:05:14
【问题描述】:

我正在用 Go 编写一个 CMS,并且有一个会话类型(用户 ID、要呈现的页面内容等)。理想情况下,我希望该类型是一个全局变量,因此我不必通过所有嵌套函数传播它,但是拥有这样的全局变量显然意味着每个新会话都会覆盖它的前任,这不必要说,将是史诗般的失败。

一些语言提供了一种在线程中保存全局变量的方法(即,该全局变量的值在该线程中被沙盒化)。虽然我知道 Goroutine 不是线程化的,但我只是想知道是否有类似的方法可供我使用,或者我是否必须通过各种嵌套例程向下传递会话类型的本地指针。

我猜频道不会这样做?据我所知(如果我在这里错了,请纠正我),但它们基本上只是一种共享全局变量的安全方式?

编辑:我忘记了这个问题!无论如何,任何好奇的人的更新。这个问题是我刚接触 Go 时写的,CMS 基本上是我的第一个项目。我来自熟悉 POSIX 线程的 C 背景,但我很快意识到更好的方法是在模式功能设计中编写代码,会话对象作为函数参数中的指针向下传递。这为我提供了我所追求的上下文相关的本地范围,同时也最大限度地减少了我正在复制的数据量。然而,作为一个有 7 年历史的项目,也是我开始向 Go 过渡的一个项目,可以公平地说,该项目无论如何都可以进行重大重写,因为犯了很多错误。不过,这是另一天的担忧 - 目前它有效,而且我还有足够多的其他项目在进行中。

【问题讨论】:

  • 看起来没有 threadlocal 功能,因此您必须传递上下文对象:groups.google.com/forum/#!topic/golang-nuts/_Vv7Bzn8yH4 尽管您可以使用全局哈希表和goroutine 的内部 id:groups.google.com/forum/#!topic/golang-nuts/Iyg3lKHV_lQ
  • 我确实考虑过使用哈希表,但如果管理不当,这是一种创建内存泄漏的简单方法,所以如果涉及到,我宁愿向下传递本地指针,因为 GC 应该管理为我休息。 runtime 看起来很有趣。谢谢。
  • 这是一个有趣的问题,因为在现实世界中,您的应用程序的很大一部分可能正在使用安全、事务,因此我可以看到这是多么乏味。在 FP 语言中,通常使用单子和词法闭包。也许 Go 有某种类似 monad 的能力?
  • 频道不是“只是一种共享全局变量的方式”。确实,通道是在 goroutine 之间共享数据的首选方式(moto 是“通过通信共享,不要通过共享进行通信”)。但首先,它是在大多数并发上下文中正确实现同步的基本技术,受 CSP en.wikipedia.org/wiki/Communicating_sequential_processes 的启发。请记住,goroutine 在写入或读取时相互等待(阻塞)。
  • 我说的是“安全共享变量的方式”,“安全”是您遗憾地漏掉的关键词。在多线程例程中锁定变量并不是一个新概念,也不是 Go 独有的。在我编写的多线程应用程序的所有其他语言中,存在锁定变量以防止在处理异步/并行进程时出现竞争条件。虽然我承认 Go 已经采用了这个概念并对其进行了更多的发展,而且我也承认我的解释被大大简化了,但你所描述的只是对我的总结的更冗长的描述。跨度>

标签: go concurrency


【解决方案1】:

你会想要使用像Context这样的东西:

http://blog.golang.org/context

基本上,该模式是为您想做的每件独特的事情创建一个Context。 (在您的情况下是一个网络请求。)使用context.WithValue 在上下文中嵌入多个变量。然后总是将它作为第一个参数传递给在其他 goroutine 中做进一步工作的其他方法。

从上下文中获取所需的变量是在任何 goroutine 中调用 context.Value 的问题。从上面的链接:

Context 可以安全地被多个 goroutine 同时使用。代码可以将单个 Context 传递给任意数量的 goroutine,并取消该 Context 以向所有 goroutine 发出信号。

我有一个实现,我明确地将变量作为方法参数发送,我发现使用上下文嵌入这些变量可以显着清理我的代码。

使用Context 也有帮助,因为它提供了通过使用通道、select 和称为“已完成通道”的概念来结束长时间运行的任务的方法。有关出色的基本审查和实施,请参阅这篇文章:

http://blog.golang.org/pipelines

我建议先阅读管道文章,以更好地了解如何管理 goroutine 之间的通信,然后阅读上下文文章,以更好地了解如何升级并开始嵌入要传递的变量。

祝你好运!

【讨论】:

    【解决方案2】:

    不要使用全局变量。使用 Go goroutine-local 变量。

    go-routine Id..

    已经有 goroutine-local 变量:它们被称为函数 参数、函数返回值和局部变量。

    罗斯

    【讨论】:

    • 这就是我开始做的事情,并没有真正回答我的问题。我有几十个嵌套函数,它们都是从高级 goroutine 调用的。这些变量需要在整个守护程序的范围内,同时从其他并行线程进行沙盒处理。这在许多语言中是一个相当普遍的问题,并且它们通常具有不需要通过函数参数向下传播指针的解决方案(这可能会很快变得相当混乱)。但是,我还没有(还)找到一个不会增加额外复杂性或开销的 Go 解决方案。
    【解决方案3】:

    如果您有多个用户,那么您不需要为每个连接提供这些信息吗?所以我认为每个连接的用户都有一个结构。在设置工作 goroutine 或通过通道传递指针时,传递指向该结构的指针将是惯用的 Go。

    【讨论】:

    • 当然。这也是我目前正在做的事情。我只是想知道 Go 是否支持将指针“全局”指向从高级 goroutine 嵌套的每个函数(作为其他语言支持),或者保持会话沙盒化的唯一方法是运行哈希表或在任何函数上都有一个会话参数(其中有几十个)。我认为鉴于 Go 对并发性的强调,他们可能在这里错过了一个技巧。然而,这并不是一个很大的不便。我只是在寻找一些“快速修复”来保持我的代码干净。还是谢谢你:)
    • 快速修复有一个讨厌的习惯,会导致问题发生。我从 PeterSO 的链接中学到了很多东西。个人仍在学习 Go,有时我会怀念我们在 C 中使用的 hack。
    猜你喜欢
    • 2013-05-27
    • 1970-01-01
    • 2015-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多