为什么atomic.StoreUint32比sync.Once中的普通分配更受欢迎?

2024-02-14

在阅读Go源码时,我对src/sync/once.go中的代码有一个疑问:

func (o *Once) Do(f func()) {
    // Note: Here is an incorrect implementation of Do:
    //
    //  if atomic.CompareAndSwapUint32(&o.done, 0, 1) {
    //      f()
    //  }
    //
    // Do guarantees that when it returns, f has finished.
    // This implementation would not implement that guarantee:
    // given two simultaneous calls, the winner of the cas would
    // call f, and the second would return immediately, without
    // waiting for the first's call to f to complete.
    // This is why the slow path falls back to a mutex, and why
    // the atomic.StoreUint32 must be delayed until after f returns.

    if atomic.LoadUint32(&o.done) == 0 {
        // Outlined slow-path to allow inlining of the fast-path.
        o.doSlow(f)
    }
}

func (o *Once) doSlow(f func()) {
    o.m.Lock()
    defer o.m.Unlock()
    if o.done == 0 {
        defer atomic.StoreUint32(&o.done, 1)
        f()
    }
}

Why is atomic.StoreUint32使用,而不是说o.done = 1?这些不是等价的吗?有什么区别?

我们必须使用原子操作(atomic.StoreUint32)以确保其他 goroutine 可以观察到效果f() before o.done在内存较弱的机器上设置为 1 吗?


请记住,除非您手动编写程序集,否则您不是针对机器的内存模型进行编程,而是针对 Go 的内存模型进行编程。这意味着即使原始分配对于您的架构来说是原子的,Go 也需要使用原子包来确保所有支持的架构的正确性。

访问done互斥体之外的flag只需要安全,不需要严格排序,因此可以使用原子操作而不是总是用互斥体获取锁。这是一种使快速路径尽可能高效的优化,允许sync.Once用于热路径。

互斥锁用于doSlow仅用于该函数内的互斥,以确保只有一个调用者能够实现f()之前done标志已设置。该标志是使用atomic.StoreUint32,因为它可能同时发生atomic.LoadUint32位于受互斥锁保护的临界区之外。

正在阅读done字段与写入(甚至原子写入)同时进行,是一种数据竞争。仅仅因为该字段是原子读取的,并不意味着您可以使用正常的赋值来写入它,因此首先检查该标志atomic.LoadUint32并写有atomic.StoreUint32

直接读取的done within doSlow is安全,因为它受到互斥锁的并发写入保护。同时读取值atomic.LoadUint32是安全的,因为两者都是读操作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么atomic.StoreUint32比sync.Once中的普通分配更受欢迎? 的相关文章

随机推荐

  • Keras 中的 CNN 模型条件层

    我正在尝试建立一个conditional CNN模型 模型是 At the first stage我的模型 我将数据提供给Model 1 then based on the prediction of Model 1 我想要train th
  • 如何使用 InteractionManager.runAfterInteractions 使导航器转换更快

    由于逻辑复杂 我必须渲染很多组件this props navigator push 缓慢的导航器转换使应用程序不可用 然后我注意到here http facebook github io react native docs performa
  • 将行添加到 Word 文档中的现有表(打开 XML)

    我需要打开包含现有表 例如 3 列 的现有 Word 文档 docx 并向该表添加新行 有什么办法可以做到这一点吗 我正在使用 Open XML 我正在创建这样的表 第一次 Table tbl new Table Set the style
  • 在等待挂起操作取消时处置 SemaphoreSlim 是否安全?

    我必须使用 SemaphoreSlim 来确保对代码某些部分的单线程访问 并且希望确保我正确处理所有内容 假设我有以下课程 public class Foo private readonly CancellationTokenSource
  • 如何在多种类型上使用 GraphQL 片段

    我有一个 Gatsby 项目 它对两种不同类型的内容有非常相似的 GraphQL 查询 常规页面和 wiki 文章 按块分页 export const query graphql query slug String page content
  • 使用 fft 和 ifft 更改频率而不使用整数

    我知道我可以通过改变变量来改变整数频率shift但我怎样才能改变频率使用带小数位的数字 例如 754 或 1 2345 or 67 456 如果我改变变量 shift 到一个非整数类似的数字5 1 我收到错误下标索引必须是小于 2 31 的
  • 验证 Google 地图中的某个点是陆地还是水域

    然后谷歌地图 将水域与水域分开 嗯 不是圣经意义上的 但是 我想知道我有哪些选项来验证 Lat Lon 的点是陆地还是水域 谷歌地图显然有这些数据 水体是蓝色的 但是 API 中有什么东西我可以用它来实现吗 如果没有 他们不提供服务是因为他
  • Android 中使用 ArrayAdapter 和 ListView 的大型数据集

    出于学习目的 我想编写一个 Android 应用程序 将显示从 0 到 Integer MAX VALUE 的数字列表 我目前有一个 应用程序将显示从 0 到 100 的数字 这很简单 因为您只需 创建一个数字数组 然后将其传递给适配器 当
  • Brightway2 - 获取即时交换的 LCA 分数

    我在对 Brightway2 的 LCA 结果进行后处理分析时遇到一些问题 运行 LCA 计算后 例如 如果我输入 top activities 我会得到一堆活动及其相关分数的列表 但是没有一个活动 分数与我的功能单元直接相关 它们似乎是我
  • CLR 字符串引用不(始终)匹配

    来自里希特和这次讨论 https stackoverflow com questions 8482479 why are 2 separate string references equal in other words why are s
  • 无法从链接的 SQL Server 查询视图

    在 SQL Server Management Studio 中 我链接了 SQL Server sql02到我的本地服务器 sp addlinkedserver sql02 GO 我可以从此服务器查询表 SELECT FROM SQL02
  • 如何从多个 mysql 列中选择不同的值并将它们放入一个 PHP 数组中?

    我有一个歌曲表 其中每首歌曲最多可以有 3 种不同的流派 因此 在我的表中 对于每首歌曲 我都有 流派 1 流派 2 和 流派 3 列 我正在尝试显示列表中可用的所有类型 这是一个随机示例集 genre1 genre2 genre3 met
  • 如何配置 WWW::Mechanize 以在代理和 https 后面工作?

    我已经使用 WWW Mechanize 编写了 Perl 代码来检索网页 当我检索 http 网页时 它工作正常 但不适用于 https 我已经检查过了 我有 Crypt SSLeay 包 还有什么可能是错误的 错误信息是 Error GE
  • 如何设置列值等于行号?

    我如何设置更改表后添加的列的值等于sql server 2008中的行号 也就是说 我希望该列的值等于行号 的行 我还希望该字段允许 NULL 值 因此 它就像自动增量但允许空值 这就是为什么不想使用具有自动增量的标识或主键列 那么如何才能
  • 如何限制 HttpModule 每个请求只能调用一次?

    这是我的 HttpModule 实现 带有模块的文件 public class HttpModuleRewriter IHttpModule region IHttpModule public void Init HttpApplicati
  • 禁用segue动画

    我想在我的故事板中显示 例如推送 segues 以连接我的视图控制器和导航控制器 然后视图控制器上的导航栏将正确显示 例如 使用显示详细信息或呈现模式 导航栏将消失 但我不想继续动画 Xcode 发出如下警告 在 iOS 9 0 之前 无法
  • 相似图像 - 如何比较它们

    我有超过 130 万张图像需要相互比较 并且每天都会添加数百张图像 我的公司拍摄图像并创建一个可供我们的供应商使用的版本 这些文件通常彼此非常相似 例如 两个不同的公司可以向我们发送两个不同的图像 一个 JPG 和一个 GIF 两者都带有麦
  • 如何使这个 CSS 汉堡菜单完全可点击?

    我正在开发一个纯 CSS 汉堡菜单图标 到目前为止 它工作得很好 只是线条之间的间隙不可点击 我如何修改此代码 以便整个按钮都可单击 而不仅仅是线条 a href title Open Menu class menu a menu widt
  • 在 ColorDialog 中设置自定义颜色

    颜色对话框中的自定义颜色设置应使用以下代码设置为 Blue Blue colorDialog1 CustomColors new int System Drawing Color Blue ToArgb 0xFF0000 colorDial
  • 为什么atomic.StoreUint32比sync.Once中的普通分配更受欢迎?

    在阅读Go源码时 我对src sync once go中的代码有一个疑问 func o Once Do f func Note Here is an incorrect implementation of Do if atomic Comp