并行计算做加法

考虑到稀疏数据结构的效率问题,特别是dynamic的速度,因此我想通过如下代码来代替动态列表,但是里面涉及到在kenerl里面做累加,计算结果会使得部分行没有成功写入数据。但是当并行计算量较小时可以成功,因此想问问如何在并行计算中,完整地将所有数据输入到一个dense field中

import taichi as ti
ti.init(arch=ti.cpu)

a = field(float, shape=(100000,))
b = field(float, shape=(1000000,))
count = field(float, shape=())

@ti.kernel
def k():
    # 初始化a中的数据
    for i in a:
        for j in range(5):
            a[i] = (i+j)*(i+j+1)/2+j # Pairing functions
    for i in a:
        if a[i] % 2 == 0:
            b[count[None]] = a[i]
            count[None] += 1

k()

照如上代码计算后,b中下标小于count[None]的元素有部分仍为零,并未赋上a的值,个人猜测是因为并行计算的原因,请问大佬们有没有什么好方法呢

  for i in a:
        for j in range(5):
            a[i] = (i+j)*(i+j+1)/2+j # Pairing functions
  • 这段代码等价于
    for i in a:
        a[i] = (i+4)*(i+4+1)/2+4 
  • 然后就是
    for i in a:
        if a[i] % 2 == 0:
            b[count[None]] = a[i]
            count[None] += 1
  • 如果想实现并行加法,应该用reduce方法, 这个是否应该是这样呢?
    for i in a:
        if i % 2 == 0:
            b[count[None]] = a[i]
            count[None] += 1
  • 但是这个过程要持续到i%4 i%8 i%16 … 直到后面2的次幂超越a数组的大小

第二个循环的是不是应该这样,保证count的原子化加的结果和当前循环里的一致 ,

for i in a:
    if a[i] % 2 == 0:
        j = ti.add(count[None],1)
        b[j] = a[i]
1 个赞

不好意思,因为这段代码是临时打的,主要的目的是想要实现一个用dense field代替dynamic field的功能,在第一个循环的时候没有考虑到其实j是没有用的,这里是有一点失误
感谢大佬给的reduce算法的解决方案!

感谢大佬的方案,这么做确实可以实现我想要的功能。想问大佬一个问题,在bilibili的视频里,不是说利用i += 1相当于原子化加法了嘛,为什么在这里不适用

count[None] += 1是原子化的,但是各并行单元对count[None]的读取还是要考虑并行的问题,举个例子,假设i=2 的并行单元执行的很慢,还没执行到b[count[None]] = a[i] 的时候,i=5,i=6…等并行单元已经执行完了,那这时候的count[None]的值可能是一个比你期望的偏大的,那在i=2的单元里,b[count[None]] 的索引访问就不对了,而j = ti.add(count[None],1)相当于在原子加的时候把加的结果同步备份了一下,,,不知道我这样解释的是不是准确,清楚

我理解了,谢谢大佬 :grinning: