f***t 发帖数: 2247 | 1 以前的帖子我没有表达清楚,把问题太过于简化了,更新一下。恳请各路大神出手指点
迷津了。没法子,灌水paper用。先谢谢了!
就是有两个二维数组,一个是tt,另一个是uu。然后根据tt中的每一列的最大值和最小
值,找出uu中相对应列的在该最大值和最小值之间的数值.
使用fortran,这是一个两层循环。具体结构,以及数据之间的关联,如下:
do i = 1, N1 !N1大小在10^9数量级
b = maxval(tt(:,i)) !tt为二维数组,列的长度为其他数值,且与i无关
c = minval(tt(:,i))
A(:) = uu(:,i) !uu为二维数组,列的长度为N2,且与i无关
do j = 1, N2 !N2大小在10^7数量级
if ((A(j).lt.b).and.(A(j).gt.c) then
.......
....... !then之后的事,与tt,uu,A,c,b都没有关系,但与j有关
else
endif
enddo
enddo
这种循环结构太浪费时间了,一个月能算出一个结果就不错了,太慢了。有啥好办法能
够节约计算时间?
先多谢各路大神指点迷津! | d****o 发帖数: 32610 | 2 A(j)还是A(i,j)?
【在 f***t 的大作中提到】 : 以前的帖子我没有表达清楚,把问题太过于简化了,更新一下。恳请各路大神出手指点 : 迷津了。没法子,灌水paper用。先谢谢了! : 就是有两个二维数组,一个是tt,另一个是uu。然后根据tt中的每一列的最大值和最小 : 值,找出uu中相对应列的在该最大值和最小值之间的数值. : 使用fortran,这是一个两层循环。具体结构,以及数据之间的关联,如下: : do i = 1, N1 !N1大小在10^9数量级 : b = maxval(tt(:,i)) !tt为二维数组,列的长度为其他数值,且与i无关 : c = minval(tt(:,i)) : A(:) = uu(:,i) !uu为二维数组,列的长度为N2,且与i无关 : do j = 1, N2 !N2大小在10^7数量级
| f***t 发帖数: 2247 | 3 多谢大蝌蚪,我犯了个错误,马上更新一下,a,b,c的数值关系。
【在 d****o 的大作中提到】 : A(j)还是A(i,j)?
| B********u 发帖数: 1 | 4 这数据是不是应该在生成的时候处理好啊?
现在你要处理就按照黄总说的,切片放到不同机器上跑好了 | f***t 发帖数: 2247 | 5 大蝌蚪,我把数据之间的关系更新了一下,不知道表达清楚了没有?
其实,就是有两个二维数组,一个是qq,另一个是pp。然后根据pp中的每一列的最大值
和最小值,找出qq中相应列的数值.
那您有什么更好的办法吗?先谢谢了!
【在 d****o 的大作中提到】 : A(j)还是A(i,j)?
| d****o 发帖数: 32610 | 6 then之后干的事情河pp qq的值有关系吗
【在 f***t 的大作中提到】 : 大蝌蚪,我把数据之间的关系更新了一下,不知道表达清楚了没有? : 其实,就是有两个二维数组,一个是qq,另一个是pp。然后根据pp中的每一列的最大值 : 和最小值,找出qq中相应列的数值. : 那您有什么更好的办法吗?先谢谢了!
| f***t 发帖数: 2247 | 7 then之后的事,与那两个数组无关,与A,c,b也都没有关系,但与j有关
【在 d****o 的大作中提到】 : then之后干的事情河pp qq的值有关系吗
| d****o 发帖数: 32610 | 8 那应该没啥好办法
FORTRAN 不懂
但是如果可以vectorize的话应该可以比for loop快些吧
【在 f***t 的大作中提到】 : then之后的事,与那两个数组无关,与A,c,b也都没有关系,但与j有关
| H********g 发帖数: 43926 | 9 可能的原因是你企图把10^9 个数字一下存在内存里 (导致内存不够 开始用硬盘做扩
展) 还不断从硬盘读新的数据 这样导致大量的硬盘io 本来可以很快的操作变成
龟速
军版的一个回帖说得有道理 你可以考虑把两个循环分开 第一步只循环tt 并把每列
的极值存在文件里 第二步再循环uu 并且把uu合理分组 每次从硬盘上读10k左右的
极值
【在 f***t 的大作中提到】 : 以前的帖子我没有表达清楚,把问题太过于简化了,更新一下。恳请各路大神出手指点 : 迷津了。没法子,灌水paper用。先谢谢了! : 就是有两个二维数组,一个是tt,另一个是uu。然后根据tt中的每一列的最大值和最小 : 值,找出uu中相对应列的在该最大值和最小值之间的数值. : 使用fortran,这是一个两层循环。具体结构,以及数据之间的关联,如下: : do i = 1, N1 !N1大小在10^9数量级 : b = maxval(tt(:,i)) !tt为二维数组,列的长度为其他数值,且与i无关 : c = minval(tt(:,i)) : A(:) = uu(:,i) !uu为二维数组,列的长度为N2,且与i无关 : do j = 1, N2 !N2大小在10^7数量级
| d****o 发帖数: 32610 | 10 他这个太大了
10^16如果8byte一个得1000T内存
肯定得分开弄
另外tt 不知每列多长
也得分
【在 H********g 的大作中提到】 : 可能的原因是你企图把10^9 个数字一下存在内存里 (导致内存不够 开始用硬盘做扩 : 展) 还不断从硬盘读新的数据 这样导致大量的硬盘io 本来可以很快的操作变成 : 龟速 : 军版的一个回帖说得有道理 你可以考虑把两个循环分开 第一步只循环tt 并把每列 : 的极值存在文件里 第二步再循环uu 并且把uu合理分组 每次从硬盘上读10k左右的 : 极值
| H********g 发帖数: 43926 | 11 想起一件事 Fortran的二维数组 在内存的存储方向和c是不同的 如果某个维度特别
长 需要考虑把数组转置 另外不要一开始就把tt全读进内存 一次读100M的数据点
而且保证所有操作在这100M里可以完成 可能问题就解决了
【在 H********g 的大作中提到】 : 可能的原因是你企图把10^9 个数字一下存在内存里 (导致内存不够 开始用硬盘做扩 : 展) 还不断从硬盘读新的数据 这样导致大量的硬盘io 本来可以很快的操作变成 : 龟速 : 军版的一个回帖说得有道理 你可以考虑把两个循环分开 第一步只循环tt 并把每列 : 的极值存在文件里 第二步再循环uu 并且把uu合理分组 每次从硬盘上读10k左右的 : 极值
| H********g 发帖数: 43926 | 12 https://web.stanford.edu/class/me200c/tutorial_77/10_arrays.html
(1,1) (1,2) (1,3) (1,4) (1,5)
(2,1) (2,2) (2,3) (2,4) (2,5)
(3,1) (3,2) (3,3) (3,4) (3,5)
Fortran stores higher dimensional arrays as a contiguous sequence of
elements. It is important to know that 2-dimensional arrays are stored by
column. So in the above example, array element (1,2) will follow element (3,
1). Then follows the rest of the second column, thereafter the third column,
and so on.
八戒如果只需要每次处理tt一列的话 似乎刚好是在处理连续的内存 不过还是要仔
细看看程序 是不是真的这样 不是的话 光读1列就够内存和硬盘折腾半天了
还要看一下 原始数据在硬盘上是不是也是以列为单位存储的 不是的话,值得先写个
小程序把数据转置一下
此外 把tt先处理完 得到极大极小值 写进文件 再处理uu这也会大大改善io操作速
度 不然的话 系统可能需要在tt和uu源文件里跳来跳去 而两步分开的话 就只需
要分别顺序读取两个文件了
分段读数据 (最好在硬盘上也是连续的) 每次处理一块 这个总体方法 是没错的
我猜慢的主要原因就是低效io操作太多
此外取极大和极小值可以自己写个函数一步完成 或者查查有没有现成的函数 如果数
组够大 把可以一步完成的事做两次也是相当可观的
点
【在 H********g 的大作中提到】 : 想起一件事 Fortran的二维数组 在内存的存储方向和c是不同的 如果某个维度特别 : 长 需要考虑把数组转置 另外不要一开始就把tt全读进内存 一次读100M的数据点 : 而且保证所有操作在这100M里可以完成 可能问题就解决了
| B********u 发帖数: 1 | 13 不是吧。
10^9 space而已
: 他这个太大了
: 10^16如果8byte一个得1000T内存
: 肯定得分开弄
: 另外tt 不知每列多长
: 也得分
【在 d****o 的大作中提到】 : 他这个太大了 : 10^16如果8byte一个得1000T内存 : 肯定得分开弄 : 另外tt 不知每列多长 : 也得分
| H********g 发帖数: 43926 | 14 简单说 当二维数组的一个维度特别长 而且不需要同时分析这个维度的话 程序要注
意在这个维度上切割数据 减少io操作
如果数据要经过几道计算的话 把一起处理的数据块限制到几兆大(cpu缓存大小以内
)还可以减少内存到cpu的io运动 可以明显提速计算
3,
column,
【在 H********g 的大作中提到】 : https://web.stanford.edu/class/me200c/tutorial_77/10_arrays.html : (1,1) (1,2) (1,3) (1,4) (1,5) : (2,1) (2,2) (2,3) (2,4) (2,5) : (3,1) (3,2) (3,3) (3,4) (3,5) : Fortran stores higher dimensional arrays as a contiguous sequence of : elements. It is important to know that 2-dimensional arrays are stored by : column. So in the above example, array element (1,2) will follow element (3, : 1). Then follows the rest of the second column, thereafter the third column, : and so on. : 八戒如果只需要每次处理tt一列的话 似乎刚好是在处理连续的内存 不过还是要仔
| f***t 发帖数: 2247 | 15 好的,多谢蝗虫。
另外,军版还有建议使用GPU,我没有折腾过GPU,您搞过没?如果有例子,麻烦给我一
个。再次感谢出手相助。
【在 H********g 的大作中提到】 : 可能的原因是你企图把10^9 个数字一下存在内存里 (导致内存不够 开始用硬盘做扩 : 展) 还不断从硬盘读新的数据 这样导致大量的硬盘io 本来可以很快的操作变成 : 龟速 : 军版的一个回帖说得有道理 你可以考虑把两个循环分开 第一步只循环tt 并把每列 : 的极值存在文件里 第二步再循环uu 并且把uu合理分组 每次从硬盘上读10k左右的 : 极值
| H********g 发帖数: 43926 | 16 根本不必要 再说你也不是做矩阵乘法 GPU似乎不会帮你什么 我觉得你的程序只要
优化对数据的管理就能提速了
【在 f***t 的大作中提到】 : 好的,多谢蝗虫。 : 另外,军版还有建议使用GPU,我没有折腾过GPU,您搞过没?如果有例子,麻烦给我一 : 个。再次感谢出手相助。
| f***t 发帖数: 2247 | 17 好的,明白了。多谢蝗虫!
【在 H********g 的大作中提到】 : 根本不必要 再说你也不是做矩阵乘法 GPU似乎不会帮你什么 我觉得你的程序只要 : 优化对数据的管理就能提速了
| H********g 发帖数: 43926 | 18 你的tt一列多长? tt uu各是多大的文件? 如果数据本身就是非常大 那还是只有
手动分块 在几个机器上分别跑 数据量特别大的话你得考虑限速的不只是内存和
CPU 硬盘IO可能是大头了
把数据和任务分成小块一个个地搞掉是基本思想
【在 f***t 的大作中提到】 : 好的,多谢蝗虫。 : 另外,军版还有建议使用GPU,我没有折腾过GPU,您搞过没?如果有例子,麻烦给我一 : 个。再次感谢出手相助。
| H********g 发帖数: 43926 | 19 军版说 找老板要大型机时也是好办法 实际就是 “放在几百个计算机上跑”
有很多对科研单位不要钱的大型机资源
当然你也得考虑你原始数据到底多大 如果大到上传都要一个月 那还是本地解决吧
【在 f***t 的大作中提到】 : 好的,多谢蝗虫。 : 另外,军版还有建议使用GPU,我没有折腾过GPU,您搞过没?如果有例子,麻烦给我一 : 个。再次感谢出手相助。
| f***t 发帖数: 2247 | 20 tt列长度很小,在1000左右,问题是那个uu太大了
【在 H********g 的大作中提到】 : 你的tt一列多长? tt uu各是多大的文件? 如果数据本身就是非常大 那还是只有 : 手动分块 在几个机器上分别跑 数据量特别大的话你得考虑限速的不只是内存和 : CPU 硬盘IO可能是大头了 : 把数据和任务分成小块一个个地搞掉是基本思想
| H********g 发帖数: 43926 | 21 1000x1Gx4 所以你的tt是可以装在一个硬盘里的? 那就先把tt处理了呗 得到一个
10G大的极值列表
然后把uu一切 放到10个普通电脑上 几天就分析完了 反正uu你也不是存在一个硬盘
上的吧?
【在 f***t 的大作中提到】 : tt列长度很小,在1000左右,问题是那个uu太大了
| f***t 发帖数: 2247 | 22 实际上的程序是这样的
【在 H********g 的大作中提到】 : 1000x1Gx4 所以你的tt是可以装在一个硬盘里的? 那就先把tt处理了呗 得到一个 : 10G大的极值列表 : 然后把uu一切 放到10个普通电脑上 几天就分析完了 反正uu你也不是存在一个硬盘 : 上的吧?
| d****o 发帖数: 32610 | 23 vectorize也很重要
比如按vector的做法,5秒就能弄1e3列
写成loop,现在十几分钟了还没出来结果
当然c++/fortran这些编译的时候自动会做一些vectorization
编译里这些优化的选项要选
import numpy as np
import time
l = int(1e3)
m = int(1e3)
n = int(1e5)#生成随机数费时间,底下重复100次充数
tt = np.random.rand(l, m)
uu = np.random.rand(l, n)*3-1.5
# vector
start = time.time()
ttmax = np.max(tt, axis=1).reshape(-1, 1)
ttmin = np.min(tt, axis=1).reshape(-1, 1)
for i in range(100):
lt = np.less(uu, ttmax)
gt = np.greater(uu, ttmin)
check = np.logical_and(lt, gt)
end = time.time()
print(end-start)
# loop
start = time.time()
for i in range(l):
tmax = max(tt[i,:])
tmin = min(tt[i,:])
for j in range(100):
for k in range(n):
check = uu[i, k] < tmax and uu[i, k] > tmin
end = time.time()
print(end-start)
【在 H********g 的大作中提到】 : 1000x1Gx4 所以你的tt是可以装在一个硬盘里的? 那就先把tt处理了呗 得到一个 : 10G大的极值列表 : 然后把uu一切 放到10个普通电脑上 几天就分析完了 反正uu你也不是存在一个硬盘 : 上的吧?
| H********g 发帖数: 43926 | 24 那就切uu吧
这种计算似乎比从硬盘读uu也慢不了多少 那么多数据你拷贝一次不也要好多天吗
然后还得把抽出的结果再拷贝
我觉得 你可以看一下怎么优化存储 是不是可以用并行存储
【在 f***t 的大作中提到】 : 实际上的程序是这样的
| f***t 发帖数: 2247 | 25 tt和uu都不是从外部的硬盘上读取的,这两个都是这个程序本身产生的数组,如果根据
最后的总数据定义一个二维数组,那size就应该是(N2,N1),这个大小已经远远超出硬
盘大小了,根本没法编译。我只有一列一列做。
帖子中的code,为了说明问题,我做了简化,实际的code是这样的
do i1 = 1, 70
do i2 = i1+1, 71
do i3 = i2+1, 72
do i4 = i3+1, 73
.................... ! 这里都是do循环,模式和上边一样,如果把这些循环
都完成,次数在10^9数量级
b = maxval(tt(:,i1)+tt(:,i2)+tt(:,i3)+tt(:,i4)......)
c = minval(tt(:,i1)+tt(:,i2)+tt(:,i3)+tt(:,i4)......)
A(:) = uu(:,i1)+uu(:,i2)+uu(:,i3)+uu(:,i4)......
do j = 1, N2 !这个是uu列长度,在10^7数量级
if ((A(j).lt.b).and.(A(j).gt.c) then
.......
.......
else
endif
enddo
enddo
enddo
enddo
【在 H********g 的大作中提到】 : 1000x1Gx4 所以你的tt是可以装在一个硬盘里的? 那就先把tt处理了呗 得到一个 : 10G大的极值列表 : 然后把uu一切 放到10个普通电脑上 几天就分析完了 反正uu你也不是存在一个硬盘 : 上的吧?
| f***t 发帖数: 2247 | 26 我把具体的code贴出来了,麻烦您看一下怎么切比较好,先谢谢您了。
【在 H********g 的大作中提到】 : 那就切uu吧 : 这种计算似乎比从硬盘读uu也慢不了多少 那么多数据你拷贝一次不也要好多天吗 : 然后还得把抽出的结果再拷贝 : 我觉得 你可以看一下怎么优化存储 是不是可以用并行存储
| H********g 发帖数: 43926 | 27 只要uu列是互相独立的 你这个程序似乎非常容易并行
不会写多线程的话 可以把uu列的生成做成用命令行参数控制 比如 compute —tt
24 34 这样 告诉这个程序只处理 24 到34 列
然后用 gnu parallel 程序 (很简单 往上有例子https://www.gnu.org/software/
parallel/parallel_tutorial.html) 直接跑很多个fortran程序的副本
这种情况 很适合在小型机到大型机那种环境里跑 有多少逻辑CPU 你需要的总时间就
缩小多少倍 放到好几个小电脑上跑也是一样的
【在 f***t 的大作中提到】 : tt和uu都不是从外部的硬盘上读取的,这两个都是这个程序本身产生的数组,如果根据 : 最后的总数据定义一个二维数组,那size就应该是(N2,N1),这个大小已经远远超出硬 : 盘大小了,根本没法编译。我只有一列一列做。 : 帖子中的code,为了说明问题,我做了简化,实际的code是这样的 : do i1 = 1, 70 : do i2 = i1+1, 71 : do i3 = i2+1, 72 : do i4 = i3+1, 73 : .................... ! 这里都是do循环,模式和上边一样,如果把这些循环 : 都完成,次数在10^9数量级
| z*****n 发帖数: 36 | 28 你这个循环加上这个看看。应该可以加速,取决于你CPU有几个core。你这个数据完全
独立不冲突
!$OMP PARALLEL
你的循环
!$OMP END PARALLEL
【在 f***t 的大作中提到】 : tt和uu都不是从外部的硬盘上读取的,这两个都是这个程序本身产生的数组,如果根据 : 最后的总数据定义一个二维数组,那size就应该是(N2,N1),这个大小已经远远超出硬 : 盘大小了,根本没法编译。我只有一列一列做。 : 帖子中的code,为了说明问题,我做了简化,实际的code是这样的 : do i1 = 1, 70 : do i2 = i1+1, 71 : do i3 = i2+1, 72 : do i4 = i3+1, 73 : .................... ! 这里都是do循环,模式和上边一样,如果把这些循环 : 都完成,次数在10^9数量级
| o**o 发帖数: 3964 | | s*l 发帖数: 9421 | 30 楼主本来就是来请教的,不要这么命
: 楼主基本上狗屁不通。你们这样瞎支招是浪费时间
【在 o**o 的大作中提到】 : 楼主基本上狗屁不通。你们这样瞎支招是浪费时间
| f***t 发帖数: 2247 | 31 好的,我马上加上这两句并行命令。谢谢大神指点迷津!
: 你这个循环加上这个看看。应该可以加速,取决于你CPU有几个core。你这个数
据完全
: 独立不冲突
: !$OMP PARALLEL
: 你的循环
: !$OMP END PARALLEL
【在 z*****n 的大作中提到】 : 你这个循环加上这个看看。应该可以加速,取决于你CPU有几个core。你这个数据完全 : 独立不冲突 : !$OMP PARALLEL : 你的循环 : !$OMP END PARALLEL
| m*******7 发帖数: 1 | 32 不确定是否误解。可以用串循环取代套循环:
for i=1, N1 do max(i)=maxval(tt(:,i)), min(i)=minval(tt(:,i))
for j=1, N2 do if min(i) <= A(j) <= max(i) then ...
【在 f***t 的大作中提到】 : 以前的帖子我没有表达清楚,把问题太过于简化了,更新一下。恳请各路大神出手指点 : 迷津了。没法子,灌水paper用。先谢谢了! : 就是有两个二维数组,一个是tt,另一个是uu。然后根据tt中的每一列的最大值和最小 : 值,找出uu中相对应列的在该最大值和最小值之间的数值. : 使用fortran,这是一个两层循环。具体结构,以及数据之间的关联,如下: : do i = 1, N1 !N1大小在10^9数量级 : b = maxval(tt(:,i)) !tt为二维数组,列的长度为其他数值,且与i无关 : c = minval(tt(:,i)) : A(:) = uu(:,i) !uu为二维数组,列的长度为N2,且与i无关 : do j = 1, N2 !N2大小在10^7数量级
| f*******y 发帖数: 2368 | 33 话糙理不糙。
本来也想随便给看看,结果没明白他到底想干啥。
【在 o**o 的大作中提到】 : 楼主基本上狗屁不通。你们这样瞎支招是浪费时间
| f*******y 发帖数: 2368 | 34 如果问题的确像你理解的,确实不用嵌套循环。
不过第一个循环仍然非常costly,整个二维数组要被access 2×N1遍。而用两个N1尺寸
的数组,一个存每列的max value so far, 一个存每列的min value so far, 循序读取
数据,边读边比较(属于某一列的数据去跟那两个数组里目前已知那一列的最大最小比
较),这样整个数据只要读一遍即可。
【在 m*******7 的大作中提到】 : 不确定是否误解。可以用串循环取代套循环: : for i=1, N1 do max(i)=maxval(tt(:,i)), min(i)=minval(tt(:,i)) : for j=1, N2 do if min(i) <= A(j) <= max(i) then ...
| n***s 发帖数: 10056 | 35 这个是对的。
套循环是最笨的。very expensive.
【在 m*******7 的大作中提到】 : 不确定是否误解。可以用串循环取代套循环: : for i=1, N1 do max(i)=maxval(tt(:,i)), min(i)=minval(tt(:,i)) : for j=1, N2 do if min(i) <= A(j) <= max(i) then ...
| t*****o 发帖数: 4919 | 36 数据on the fly的话那就跟I/O没关系
b = maxval(tt(:,i1)+tt(:,i2)+tt(:,i3)+tt(:,i4)......)
c = minval(tt(:,i1)+tt(:,i2)+tt(:,i3)+tt(:,i4)......)
显然这里你先算好
sum=tt(:,i1)+tt(:,i2)+tt(:,i3)+tt(:,i4)......
比算两遍要快
b = maxval(sum)
c = minval(sum)
不要用maxval, minval, 把max min放在一个loop里
Do I=1,N
if(max
max=sum[i]
if(min>sum[i]
min=sum[i]
enddo
Why, 因为这个loop就是把所有数据遍历一次, 分开来就是遍历两次,主要花销是内存
读取的bandwith。 但是如果你把他们放在一起, 数据还在register里, 基本没有额
外花销。
另外实现多线程, 用openmp也好, 自己写也好。
考虑 SIMD/vectorization 比如AVX512的intrinsics __m512 _mm512_max_ps(__m512 a
, __m512 b), 可以一次处理16个数据。
内嵌循环也可以考虑多线程和SIMD
【在 f***t 的大作中提到】 : tt和uu都不是从外部的硬盘上读取的,这两个都是这个程序本身产生的数组,如果根据 : 最后的总数据定义一个二维数组,那size就应该是(N2,N1),这个大小已经远远超出硬 : 盘大小了,根本没法编译。我只有一列一列做。 : 帖子中的code,为了说明问题,我做了简化,实际的code是这样的 : do i1 = 1, 70 : do i2 = i1+1, 71 : do i3 = i2+1, 72 : do i4 = i3+1, 73 : .................... ! 这里都是do循环,模式和上边一样,如果把这些循环 : 都完成,次数在10^9数量级
|
|