能力值:
( LV2,RANK:10 )
|
-
-
51 楼
使用环境:winxp 下的硬件访问,每使用一次GetPosValue都会调用几百次IO。
不太清楚入口技术是啥,不知道是不是说的需要积累哪方面知识??因为这个问题可以抛开物理设备等概念,只要用算法就可以了。
技术限制当然就是用算法了,不过速度的关键还是在于每一段连续的0、1、2、3最少保证在多少数目,最多保证在多少数目。。
感谢大家关注,我因为工作忙,这些天没有讨论这个了,但问题依然没有解决。
|
能力值:
( LV2,RANK:10 )
|
-
-
52 楼
还不太懂,只能帮你顶下了……
|
能力值:
( LV2,RANK:10 )
|
-
-
53 楼
算法固然重要,但是硬件的配置也很重要,还有实现算法的途径!
比如,1G数据如果使用字符型,访问速度会比直接内存访问慢;使用多核CPU会比单核快。
算法用时对比,必须是相同条件下,否则没有意义。
|
能力值:
( LV2,RANK:10 )
|
-
-
54 楼
我觉得先用一定的 GetPosValue次数去获得大致的连续数量,以这个为基准再做二分法会靠谱点吧,然后把连续次数的结果都记录下(黑盒 GetPosValue花费IO多,但用主机来进行运算和预测就不用那么费时间了 ),然后获取大致的连续范围,然后就可以越来越准确和快速了
|
能力值:
( LV4,RANK:50 )
|
-
-
55 楼
先关注一下,晚上回去想想
|
能力值:
( LV4,RANK:50 )
|
-
-
56 楼
我觉得楼主的20,40,60这样二分的步长有点太保守了
不是说数据重复的次数差不多吗,前几个的重复长度可以记录下来,
做为后面查找时的步长,
比如前四个0,1,2,3都是2W左右和重复,那么查找下个数据的步长先设置为2W,然后再在2W的左右进行查找
|
能力值:
( LV2,RANK:10 )
|
-
-
57 楼
如果黑盒里数据都是0、1、2、3的话不管有没有其他规律都可压缩,方法是用2比特表示一个数据,这样就可将4个数据变成一个字节,定位查找也很容易实现。
如果出现相邻字符重复的概率很高且黑盒里数据都是0、1、2、3的话,则可用一个字节中6比特表示重复次数,另外两比特表示值(0、1、2、3),这样可大幅压缩空间,为了便于定位查找,可通过等间距的插入位置参数,这样定位查找时先采用二分法,然后查找。
|
能力值:
( LV2,RANK:10 )
|
-
-
58 楼
if ((F(max) == F(max-1)) && (F(max-1) != F(min)))
{//说明 max 处相邻的两个是 相等 的,并且 不等于 min的位置处,此时要max设为3W
....小值不变min = 2W,大值 max 为3W后递归....
}
if ((F(max) == F(max-1)) && (F(max-1) == F(min)))
{//说明 max 处相邻的两个是 相等 的,并且 等于 min处位置的值,
...此时要将 mix 设为3W,max 设为4W(这里的将max设为4W应该可以优化的,因为前面已经读过这里的值)...
}
if ((F(max) != F(max-1)) && (F(max-1) == F(min)))
{//max 不等于 max-1 ,说明找到分隔点了,直接返回max
return max
}
这些地方不要用递归,只用一个循环就可
|
能力值:
( LV2,RANK:10 )
|
-
-
59 楼
LZ牛淫把KX给我把。。
我注册一年了还没到正式会员,
|
能力值:
( LV2,RANK:10 )
|
-
-
60 楼
ReadAll(int m_BoxLength)//遍历并保存到文件或内存
{
int m_Current=0;
while(m_Current<m_BoxLength)
{
BOOL IsEnd=FALSE;
int m_HeiPos=m_Current+20000; //20000为最少重复字符数值
if(m_HeiPos>m_BoxLength){m_HeiPos=m_BoxLength;IsEnd=TRUE;}
BYTE m_Vaule
m_Vaule=GetPosValue(m_Current);
if(IsEnd==FALSE)
{
while(m_Vaule==GetPosValue(m_HeiPos))
{
m_HeiPos+=20000;
if(m_HeiPos>m_BoxLength){m_HeiPos=m_BoxLength;IsEnd=TRUE; break;}
}
}
if(IsEnd==FALSE)
{
int m_LowPos=m_HeiPos-20000;
while(1)
{
int m_MidPos=(m_LowPos+m_HeiPos)/2;
if(m_Vaule==GetPosValue(m_MidPos)) m_LowPos=m_MidPos;
else m_HeiPos=m_MidPos;
if(m_HeiPos=m_LowPos+1) break;
}
}
SaveVaule(m_Vaule,m_HeiPos-m_Current);
//SaveVaule(int m_Vaule,int m_SameLength)的作用是将读取到值保存到文件中或内存中,自己写吧
m_Current=m_HeiPos;
}
}
|
能力值:
( LV2,RANK:10 )
|
-
-
61 楼
那種應該是用到演算法的技巧了吧,他沒有遍歷,但是他的也很準確的那種方法,那種我有學到。演算法有不少這種東西。
|
能力值:
( LV2,RANK:10 )
|
-
-
62 楼
我虽然在60楼给出了遍历算法,但没经调试,所以我希望楼主采用该法后,能公布测试结果(包括 DEBUG版本和RELEASE版本)
|
能力值:
( LV2,RANK:10 )
|
-
-
63 楼
这,一直没关注了。。马上测试。。谢谢你。
|
能力值:
( LV2,RANK:10 )
|
-
-
64 楼
我觉得啊,你应该给出你平均调用一次GetPosValue需要多少时间,分别调用100次,500次,1000次给出各自的平均时间。假设这里记为t0,平均连续串长度是20k吧(2W),就是占用20KByte=160Kb。1G/160Kb=1024*1024/160= 6553.6(个),就是至少要使用65534次GetPosValue吧,楼主可以测试一下调用65534次GetPosValue需要多少时间吗?如果用二分,需要在平均2*2W个数据(保守估计)中找到分割点,所以平均每次找到一个分割点需要log2(40k) = 15.28次 算作16次(最坏次数)吧,所以调用65534*16次GetPosValue。
猜测。还有外国人是1.2G,30秒,你是1G,6min。6*60、30* 1.2/1 = 14.4 和16差不多啊。总感觉楼主是不是哪里搞错了啊!比如问题的描述,自己写的代码,或者实验环境什么的...
|
能力值:
( LV2,RANK:10 )
|
-
-
65 楼
对了,你同时也需要对顺序读取和随机读取分别进行测试,计算平均时间,针对GetPosValue!
|
能力值:
( LV2,RANK:10 )
|
-
-
66 楼
VOID ReadAll(DWORD m_BoxLength)//遍历并保存到文件或内存
{
DWORD dwPos = 0;
DWORD m_Current = 0;
while(m_Current < m_BoxLength)
{
BOOL IsEnd = FALSE;
DWORD m_HeiPos = m_Current + 20000; //20000为最少重复字符数值
if(m_HeiPos > m_BoxLength)
{
m_HeiPos = m_BoxLength;
IsEnd = TRUE;
}
BYTE m_Vaule = GetPosValue(m_Current);
if(IsEnd == FALSE)
{
while(m_Vaule == GetPosValue(m_HeiPos))
{
m_HeiPos += 20000;
if(m_HeiPos > m_BoxLength)
{
m_HeiPos = m_BoxLength;
IsEnd = TRUE;
break;
}
}
}
if(IsEnd == FALSE)
{
int m_LowPos = m_HeiPos - 20000;
while(1)
{
//int m_MidPos = (m_LowPos+m_HeiPos) / 2; //取中间值
int m_MidPos = m_LowPos + (m_HeiPos - m_LowPos) / 2; //修改:取中间值
if(m_Vaule == GetPosValue(m_MidPos))
m_LowPos = m_MidPos;
else
m_HeiPos = m_MidPos;
if (GetPosValue(m_LowPos) != GetPosValue(m_LowPos + 1))//修改这里的退出条件
break;
//if(m_HeiPos = m_LowPos + 1) //修改后代码
// break;
}
}
memset(pFile + dwPos, m_Vaule, m_HeiPos - m_Current); //pFile是内存映射的文件缓冲指针
dwPos += (m_HeiPos - m_Current);
//SaveVaule(int m_Vaule,int m_SameLength)的作用是将读取到值保存到文件中或内存中,自己写吧
m_Current = m_HeiPos;
}
}
修改了一下并且做了测试。。你的思路和我的应该是一样。也是二分比较相邻的是否不等,并用它来作为退出的条件。
现在这个速度就取决于最少重复次数20000..合理的设置它的值,能有效的控制速度。
谢谢你提供这个算法,比我自己写的二分要好多了。。。学习。。
|
能力值:
( LV2,RANK:10 )
|
-
-
67 楼
FK [word packed]
|
能力值:
( LV2,RANK:10 )
|
-
-
68 楼
那就这样做测试:生成一个500M的文件,文件填充0、1、2、3、4、5这样的数据,连续的数量控制在5W-6W左右(之前说的是2W,这里可以改大点)。每调用一次函数只能取某个偏移的值。
要把所有的分界找出来。看看多长时间。
我这里调用GetPosValue是读硬件上面的数据,实在无法提供测试文件。。。一个函数的调用有几百次IO。
|
能力值:
( LV2,RANK:10 )
|
-
-
69 楼
我是让你自己测试一下时间,然后公布出来!
这样就可以估算用二分法的时间了。到底是你自己写的程序有问题,还是什么的就清楚了。
分别调用100次,500次,1000次,2000次,。。。给出各自的平均时间
楼主可以测试一下调用65534次GetPosValue需要多少时间
我是让你测试,明白吗?然后把测试结果公布出来。
比如时间为t0,那么二分法差不多是用了65534*16*t0的IO时间
|
能力值:
( LV2,RANK:10 )
|
-
-
70 楼
自我感觉lz是由于二分法使用不当造成的。
|
能力值:
( LV2,RANK:10 )
|
-
-
71 楼
release 下测试了一组数据:
1000次:
开始时间 : 11694796毫秒, 11694秒
结束时间 : 11696328毫秒, 11696秒
差值:1532
----------------------------------
3000次:
开始时间 : 11696328毫秒, 11696秒
结束时间 : 11700640毫秒, 11700秒
差值:4312
----------------------------------
5000次:
开始时间 : 11700640毫秒, 11700秒
结束时间 : 11707828毫秒, 11707秒
差值:7188
----------------------------------
8000次:
开始时间 : 11707828毫秒, 11707秒
结束时间 : 11719546毫秒, 11719秒
差值:11718
----------------------------------
15000次:
开始时间 : 11719546毫秒, 11719秒
结束时间 : 11741390毫秒, 11741秒
差值:21844
----------------------------------
20000次:
开始时间 : 11741390毫秒, 11741秒
结束时间 : 11770437毫秒, 11770秒
差值:29047
----------------------------------
使用的二分法是60楼的兄弟提供的
|
能力值:
( LV2,RANK:10 )
|
-
-
72 楼
|
能力值:
( LV2,RANK:10 )
|
-
-
73 楼
那就是平均调用一次1.4ms~1.5ms,那就记为t0=1.45ms吧。
那么二分法差不多是用了65534*16*t0的IO时间=6554*16*1.45ms = 152.0s=2.53min.
麻烦你再统计一下,你使用上面的方法总共得到了多少连续的字符串。假设为m个,则总IO时间平均为m*log2(numOfALLBtyes/m)*1.45ms
你把步进的策略改变一下。
设下一个要读取的数据的位置为pnext。当前连续字符串的开头位置为pcurrent。上一个连续字符串的长度为lenLast,两个连续字符串长度差最大值为MAX_DELTA,则取pnext = pcurrent + 2*(lenLast - MAX_DELTA )【比较保守的步进方式,你还可以再试试大胆一点比如pnext = pcurrent + 2*lenLast - MAX_DELTA 】。明白我的意思吗?
这样会大大缩短时间的。当平均长度为10W时,则平均有1342个连续字符串。
IO时间=1342*log2(10W)*1.45ms=1342*16.6*1.45ms=32s。大约是那个外国人的时间吧(至少数量级一样了O(∩_∩)O~)。
|
能力值:
( LV2,RANK:10 )
|
-
-
74 楼
先膜拜一下。
我测试将156 301 488的数据量整理出来,得花3.6分钟. 我把步进改为1000和2000和3000效果不大。
改大后,二分时间长。改小后,二分时间短,但前面时间又变长了。
我把你的分析过程一字一字的啃了几遍,我发现我的数学好差。
|
能力值:
( LV2,RANK:10 )
|
-
-
75 楼
步长不是你随意改的,是根据前一个连续字符串的长度定的(程序动态的更改的),最少是2W。
|
|
|