Otis
2022 年6 月 19 日 04:17
#1
考虑到稀疏数据结构的效率问题,特别是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 个赞
Otis
2022 年6 月 21 日 03:01
#4
不好意思,因为这段代码是临时打的,主要的目的是想要实现一个用dense field代替dynamic field的功能,在第一个循环的时候没有考虑到其实j是没有用的,这里是有一点失误
感谢大佬给的reduce算法的解决方案!
Otis
2022 年6 月 21 日 03:03
#5
感谢大佬的方案,这么做确实可以实现我想要的功能。想问大佬一个问题,在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)相当于在原子加的时候把加的结果同步备份了一下,,,不知道我这样解释的是不是准确,清楚