Algorithm 外部合并中的过程数

Algorithm 外部合并中的过程数,algorithm,sorting,external-sorting,Algorithm,Sorting,External Sorting,至少在标题搜索中,似乎没有任何预先存在的问题。我正在寻找外部合并的最佳通过次数。因此,如果我们有1000个数据块,一个过程就是1000路合并。两次传递可以是5组200个区块,然后是1组5个区块的最终合并。等等我做了一些数学计算,这肯定有一个缺陷,因为看起来两次传球都比不上一次传球。不过,这很可能是对数据读取方式的误解 首先,一个数值例子: 数据:100GB 内存:1 GB 由于我们有1GB内存,我们可以一次加载1GB,使用快速排序或合并排序进行排序。现在我们有100个块要排序。我们可以进行100

至少在标题搜索中,似乎没有任何预先存在的问题。我正在寻找外部合并的最佳通过次数。因此,如果我们有1000个数据块,一个过程就是1000路合并。两次传递可以是5组200个区块,然后是1组5个区块的最终合并。等等我做了一些数学计算,这肯定有一个缺陷,因为看起来两次传球都比不上一次传球。不过,这很可能是对数据读取方式的误解

首先,一个数值例子:

数据:100GB
内存:1 GB

由于我们有1GB内存,我们可以一次加载1GB,使用快速排序或合并排序进行排序。现在我们有100个块要排序。我们可以进行100路合并。这是通过使
RAM/(chunks+1)
size bucket=
1024MB/101
=
10.14MB
来实现的。100个块中的每个块都有100个
10.14MB
存储桶,还有一个大小为
10.14MB
的输出存储桶。当我们合并时,如果任何输入存储桶为空,我们将进行磁盘搜索以重新填充该存储桶。同样,当输出bucket满时,我们会写入磁盘并清空它。我声称“磁盘需要读取的次数”是
(数据/ram)*(块+1)
。这是因为我们有
ram/(chunks+1)
大小的输入存储桶,我们必须在给定的过程中读取整个数据,所以我们读取
(data/bucket\u size)
次。换句话说,每次输入桶清空时,我们都必须重新填充它。我们在这里对100个块执行此操作,因此
numChunks*(chunk\u size/bucket\u size)
=
datasize/bucket\u size
100*(1024MB/10.14MB)
。BucketSize=
ram/(块+1)
so
100*(1024/10.14)
=
(数据/ram)*(块+1)
=
1024*100MB/1024MB*101
=10100次读取

对于双通道系统,我们先进行一组B#块,然后进行一组a#块的最终合并。使用前面的逻辑,我们有numReads=
A*((数据/ram)*(B+1))+1*((数据/ram)*(A+1))
。我们还有
A*B
=
Data/Ram
。例如,10组10个区块,其中每个区块为GB。这里,A=10b=10。10*10=100/1=100,即
Data/Ram
。这是因为
Data/Ram
是块的原始数量。对于2次传递,我们希望将
数据/Ram
分解为一组B#块

我将尝试在这里分解公式,让D=data,A=#groups,B=#chunks/group,R=RAM

A*(D/R)*(B+1)+1*(D/R)*(A+1)
-这是B区块外部合并读取次数加上A区块最终合并读取次数的一倍


(D^2/R^2)*[1+2/B]+D/R
是2次外部合并的读取次数。对于1次传递,我们有
(数据/ram)*(chunks+1)
,其中chunks=1次传递的数据/ram。因此,对于一个过程,我们有
D^2/R^2+D/R
。我们看到,当块大小B变为无穷大时,2次传递只会达到这个值,即使这样,附加的最终合并也会给我们提供
D^2/R^2+D/R
。所以一定是我遗漏了什么,或者我的数学有缺陷。感谢所有花时间帮助我的人

您忽略了这样一个事实,即从磁盘读取数据块所需的总时间是

  • 旋转硬盘驱动器的访问时间大致恒定,约为几毫秒
  • 传输时间取决于数据块的大小和传输速率
随着区块数量的增加,输入缓冲区(您称之为bucket)的大小减小。输入缓冲区越小,恒定访问时间对填充缓冲区所需总时间的影响就越明显。在某一点上,填充缓冲区的时间几乎完全由访问时间决定。因此,合并过程的总时间开始随着缓冲区的数量而不是读取的数据量而变化

这就是额外的合并过程可以加快进程的地方。它允许使用更少和更大的输入缓冲区,并减轻访问时间的影响

编辑:这里是包络线计算的快速回顾,以了解盈亏平衡点的位置

总传输时间可以很容易地计算出来。所有数据每次必须读写一次:

total_transfer_time = num_passes * 2 * data / transfer_rate
缓冲区读取的总访问时间为:

total_access_time = num_passes * num_buffer_reads * access_time
因为只有一个输出缓冲区,所以它可以比输入缓冲区大,而不会浪费太多内存,所以我将忽略写入的访问时间。缓冲区读取的数量为
data/buffer\u size
,对于一次通过方法,缓冲区大小约为
ram/num\u chunks
,而chunks的数量为
data/ram
。因此,我们:

total_access_time1 = num_chunks^2 * access_time
对于双通道解决方案,使用
sqrt(num_chunks)
缓冲区来最小化访问时间是有意义的。因此,缓冲区大小为
ram/sqrt(num_chunks)
,我们有:

total_access_time2 = 2 * (data / (ram / sqrt(num_chunks))) * acccess_time
                   = 2 * num_chunks^1.5 * access_time
因此,如果我们使用
传输速率=100 MB/s
访问时间=10 ms
数据=100 GB
ram=1 GB
,则总时间为:

total_time1 = (2 * 100 GB / 100 MB/s) + 100^2 * 10 ms
            = 2000 s + 100 s = 2100 s
total_time2 = (2 * 2 * 100 GB / 100 MB/s) + 2 * 100^1.5 * 10 ms
            = 4000 s + 20 s = 4020 s
访问时间的影响仍然很小。因此,让我们将数据更改为1000 GB:

total_time1 = (2 * 1000 GB / 100 MB/s) + 1000^2 * 10 ms
            = 20000 s + 10000 s = 30000 s
total_time2 = (2 * 2 * 1000 GB / 100 MB/s) + 2 * 1000^1.5 * 10 ms
            = 40000 s + 632 s = 40632 s
现在,一次性版本中有一半的时间用于磁盘查找。让我们尝试使用5000 GB:

total_time1 = (2 * 5000 GB / 100 MB/s) + 5000^2 * 10 ms
            = 100000 s + 250000 s = 350000 s
total_time2 = (2 * 2 * 5000 GB / 100 MB/s) + 2 * 5000^1.5 * 10 ms
            = 200000 s + 7071 s = 207071 s

现在双通道版本更快了。

您忽略了这样一个事实,即从磁盘读取数据块所需的总时间是

  • 旋转硬盘驱动器的访问时间大致恒定,约为几毫秒
  • 传输时间取决于数据块的大小和传输速率
随着区块数量的增加,输入缓冲区(您称之为bucket)的大小减小。输入缓冲区越小,恒定访问时间对填充缓冲区所需总时间的影响就越明显。在某个特定的时间点上,需要记录
total_time1 = (2 * 5000 GB / 100 MB/s) + 5000^2 * 10 ms
            = 100000 s + 250000 s = 350000 s
total_time2 = (2 * 2 * 5000 GB / 100 MB/s) + 2 * 5000^1.5 * 10 ms
            = 200000 s + 7071 s = 207071 s
c ( rM + k(c/N+1) ) + c ( rM + k(N+1) ) = c ( 2rM + k(c/N + N) + 2k )