【问题标题】:why atomic operation is faster using separate threads?为什么原子操作使用单独的线程更快?
【发布时间】:2017-07-07 15:16:28
【问题描述】:

我有两段代码,我的桌面上有 32 个内核。

代码 A 使用 32 个线程并执行以下操作,

1) 将值写入内存中的一些随机位置 2) 以原子方式向全局变量添加值。

代码 B 使用 16 个线程将值写入随机位置,并使用另外 16 个线程以原子方式将值添加到全局变量。

我想知道为什么代码 B 在每秒对全局变量执行多少原子操作方面更快。

这里是代码A

var a uint64 = 0

const N = 10 * 1024 * 1024

var data [N]uint64

func main() {

    for i := 0; i < 32; i ++ {
        go func(id int) {
            source := rand.NewSource(int64(id))
            local_rand := rand.New(source)
            for {
                atomic.AddUint64(&a, uint64(1))
                data[local_rand.Int31n(N)] = uint64(1)
            }
        }(i)

    }

    var b uint64 = 0

    for {
        c := atomic.LoadUint64(&a)

        fmt.Println(c - b)
        b = c
        time.Sleep(time.Second)
    }

}

这里是代码 B

var a uint64 = 0

const N = 10 * 1024 * 1024

var data [N]uint64

func main() {

    for i := 0; i < 16; i ++ {
        go func(id int) {
            source := rand.NewSource(int64(id))
            local_rand := rand.New(source)
            for {
                data[local_rand.Int31n(N)] = uint64(1)
            }
        }(i)

    }
    for i := 0; i < 16; i++ {

        go func() {
            for {
                atomic.AddUint64(&a, uint64(1))
            }

        }()
    }
    var b uint64 = 0

    for {
        c := atomic.LoadUint64(&a)

        fmt.Println(c - b)
        b = c
        time.Sleep(time.Second)
    }

}

【问题讨论】:

    标签: memory go concurrency cpu cpu-cache


    【解决方案1】:

    原子操作很昂贵。为了保持原子性,您需要确保该代码块的互斥执行。通常这是使用诸如加载链接、存储条件等指令来实现的。在代码 A 中,您有 32 个原子操作,但在代码 B 中,您只有 16 个。更少的原子工作,减少了执行时间!

    作为一个实验,尝试使用代码 A 中的内存操作更改原子操作的顺序。(只需先执行内存,然后执行原子操作)。您应该会看到执行时间减少了。

    【讨论】:

    • 我不认为将代码 A 中的线程数更改为 16 会提高性能。
    • 我看不出和你提议的有什么不同。首先是内存,然后是原子。我错过了什么吗?
    • 如果你让所有线程都先做原子,它们都会争夺锁。如果你先有内存,他们都会先做内存,但是由于缓存的内容与否,内存操作将在不同的时间完成。这意味着原子操作将在不同的时间开始。因此,您将不会遇到与之前相同的争用。所以我期待更少的执行时间。可能是你所有的数据都被缓存了,没有按照我的预期做......无论如何只是我脑海中闪过的一个理论。
    • 你可以尝试另一个实验。产生 32 个线程,让奇数线程执行内存,偶数线程执行原子。现在您应该看到与代码 B 相同的时间。
    • 我的意思是这两个操作都在一个 for 循环中。顺序真的重要吗?我无法使用我的笔记本电脑,所以我无法尝试您所说的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多