【性能优化】4.3 [遍历技术] 并行遍历

 

【性能优化】4.2 [遍历技术] 遍历复用

4.3 并行遍历

我们在第二章讲过外存数据集分段的方法,它不仅可以用于二分法查找,更重要的是可以用于分段并行。让多个 CPU 分担计算量,经常可能获得接近于线性增长的性能提升。

SPL 提供了很方便并行计算语法:


A

B

1

=file("orders.txt")


2

fork to(4)

=A1.cursor@t(area,amount;A2:4)

3


return B2.groups(area;sum(amount):amount)

4

=A2.conj().groups(area;sum(amount))

fork 语句将启动多个线程并行执行自己的代码块,线程的数量由 fork 后参数序列的长度决定,fork 同时会将这些参数依次分配给每个线程,代码块中引用 fork 所在格值即可得到。当所有线程执行完毕之后,每个线程的计算结果,也就是代码块中 return 的值,将被收集到 fork 所在格中,按线程的次序拼成一个序列。然后代码继续执行。

本例中, A2 会产生 4 个线程,每个线程分别得到 1、2、3、4 作为参数,在 B2 中可以生成相应的分段游标并进行分组汇总计算,4 个线程都结束后,每个线程的返回值(都是一个序表)会收集在 fork 格,也就是 A2 中,然后再把这些序表合并起来再做一次汇总就得到了针对原数据表的分组汇总结果。

除了分段数据表外,还可以使用多文件上的并行。比如订单放到了 12 个文件中,每个月放一个文件,我们来计算各地区金额在 50 以上的订单数量:


A

B

1

fork to(12)

=file("orders"\A2\".txt")

2


=B1.cursor@t(area,amount;A2:4)

3


=B2.select(amount>=50)

4


return B2.groups(area;count(1):quantity)

5

=A1.conj().groups(area;sum(quantity))

这时会启动 12 个线程计算。注意,在线程中用 count 计数后,在线程外要用 sum 来合计,而不能再用 count。

SPL 简化了并行计算的机制,假定各线程都是同时启动,并且等待所有线程都结束才完成整个任务。这样无法用于处理系统级的复杂并行任务,但可以语法代码简单很多,对于大多数结构化数据计算已经够用了。

并行执行时,要先设置集算器选项中的并行数:

imagepng

设置之后,SPL 将物理上最多会生成这个数量的线程。如果 fork 后的参数序列更长,则会强制串行执行。比如刚才的例子中,fork 的参数序列长度为 12,而这里设置的并行数是 4,SPL 实际上只会启动 4 个线程,依次将 fork 的前 4 个任务放进去线程中执行,有某个线程执行完出现空闲时,再把某个还未执行的任务填进去,依此规则反复,直到所有任务都执行完。这样,逻辑上看起来有 12 个线程,实际上只有 4 个线程。

在这种机制下,把任务拆碎一些会有好处。因为每个任务实际的执行时候不一定总是一样长,如果物理上每个线程只执行一个任务,执行快的线程结束之后就只能等待其它慢线程。如果任务拆碎了,快的线程可以多执行一些任务,总的等待量会更少,负载更为均衡,总体性能也会更好。坏处在于会增加更多的内存用于存储线程的返回结果,而且线程切换调度也有成本,所以并不是拆得越碎就越好,具体数值要看实际情况来确定。

通常,每个线程会对应由一个 CPU 执行,如果产生的线程数超过了 CPU 的数量,操作系统就会使用分时技术,在 CPU 上切换不同的线程,而这些机制都会消耗 CPU 和内存资源,导致总体性能反而会下降。所以,设置最大并行数时不宜超过 CPU 数量,通常要略少一点,因为某些 CPU 还需要负担操作系统事务等其它任务。

有些服务器的 CPU 很多,可能多达几十个,但我们有时会发现把并行数量设置更多,也不会获得更好的性能。这一方面是因为线程多了调度成本会上升,更可能的原因是硬盘并没有同样的并行能力。多个线程会共享同一套硬盘,涉及外存计算时都要从硬盘中读取数据,而硬盘总的吞吐能力是确定的,如果已经达到极限,那也没办法跑得更快,这时候就会发生 CPU 闲置等待硬盘的现象。特别是对于机械硬盘,并行读取时还会造成较严重的磁头跳动现象,导致硬盘性能严重下降,极有可能出现并行数量越多性能越差的结果。

服务器的 CPU 和硬盘配置要均衡以适应计算任务,有些服务器把 CPU 配得很多很强,又为了容量大而配置了低速的机械硬盘,结果常常发挥不了 CPU 的效能,造成浪费。如果把购买 CPU 的钱花到内存或高速固态硬盘上,很可能成本更低而得到更好的性能。

【性能优化】4.4 [遍历技术] 数据库并行加载

【性能优化】 前言及目录