关于fseek, fwrite, fread的耗时问题

时间:2021-10-05 07:06:10
现在有一个文件存储着一些样本,目的是随机打乱这些样本
我的做法是这样的
1. 将样本拷贝
2. 生成随机样本的位置索引
3. fread原数据的一个样本
4. 根据位置索引调用fseek,找到在随机化之后的位置
5. fwrite这个样本的数据到拷贝的文件中

这个过程极其耗时,但是我将fread, fseek, fwrite三个函数随便选一个注释掉,效率都会有大幅度提升,不知道这是为什么?

13 个解决方案

#1


数据量很大吗,没完全明白你的意思, 打乱(读取出来在写回去?),生成索引(索引存在哪里),按索引查找(怎么查找),你仔细想想你的逻辑处理上有没有可优化的。

#2


引用 1 楼 a30037338 的回复:
数据量很大吗,没完全明白你的意思, 打乱(读取出来在写回去?),生成索引(索引存在哪里),按索引查找(怎么查找),你仔细想想你的逻辑处理上有没有可优化的。



数据量很大,400万的样本量,是写到拷贝的样本里面,肯定不能直接写到原样本,这样就覆盖了,索引是提前生成好的,每次都要fread这个索引文件来获取fseek的位置

#3


引用 1 楼 a30037338 的回复:
数据量很大吗,没完全明白你的意思, 打乱(读取出来在写回去?),生成索引(索引存在哪里),按索引查找(怎么查找),你仔细想想你的逻辑处理上有没有可优化的。


我是用MATLAB的randperm来生成的索引 = =

#4


仅供参考:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int d[6];
int i,n,a,b,t;
int c,j;
void main() {
    srand(time(NULL));
    printf("shuffle 0..n-1 demo\n");
    for (n=1;n<=5;n++) {/* 测试1~5个元素 */
        printf("_____n=%d_____\n",n);
        j=1;
        for (c=1;c<=n;c++) j=j*c;/* j为n! */
        j*=n*2;
        for (c=1;c<=j;c++) {/* 测试n*2*n!次 */
            for (i=0;i<n;i++) d[i]=i;/* 填写0~n-1 */
            for (i=n;i>0;i--) {/* 打乱0~n-1 */
                a=i-1;b=rand()%i;
                if (a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
            }
            printf("%04d:",c);
            for (i=0;i<n;i++) printf("%d",d[i]);
            printf("\n");
        }
    }
    printf("shuffle 1..n demo\n");
    for (n=1;n<=5;n++) {/* 测试1~5个元素 */
        printf("_____n=%d_____\n",n);
        j=1;
        for (c=1;c<=n;c++) j=j*c;/* j为n! */
        j*=n*2;
        for (c=1;c<=j;c++) {/* 测试n*2*n!次 */
            for (i=1;i<=n;i++) d[i]=i;/* 填写1~n */
            for (i=n;i>1;i--) {/* 打乱1~n */
                a=i;b=rand()%i+1;
                if (a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
            }
            printf("%04d:",c);
            for (i=1;i<=n;i++) printf("%d",d[i]);
            printf("\n");
        }
    }
}

#5


再供参考:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
unsigned long ulrand(void) {
    return (
     (((unsigned long)rand()<<24)&0xFF000000ul)
    |(((unsigned long)rand()<<12)&0x00FFF000ul)
    |(((unsigned long)rand()    )&0x00000FFFul));
}
unsigned __int64 ullrand(void) {
    return (
     (((unsigned __int64)ulrand())<<32)
    | ((unsigned __int64)ulrand()));
}
int i;
unsigned long ul;
unsigned __int64 ull;
void main() {
    srand(time(NULL));
    for (i=0;i<10;i++) {
        ul=ulrand();
        printf("%010lu 0x%08x\n",ul,ul);
    }
    for (i=0;i<10;i++) {
        ull=ullrand();
        printf("%020I64u 0x%016I64x\n",ull,ull);
    }
}
//3971076432 0xecb1d150
//2433428051 0x910b2a53
//1415415336 0x545d8628
//1312330759 0x4e389407
//1845758378 0x6e0409aa
//0008069933 0x007b232d
//4202720757 0xfa806df5
//2669855255 0x9f22c217
//0312068736 0x1299ca80
//2084555989 0x7c3fccd5
//03502077880857307931 0x3099e1472040ab1b
//16884702393146816355 0xea52835e19b43763
//01877364819396611730 0x1a0dbd5b45f34e92
//07839440151924835771 0x6ccb4948756a05bb
//09471412086917299176 0x8371371c820bfbe8
//04411255971577469925 0x3d37edef2f321be5
//13735846279546091130 0xbe9f876a65b7367a
//04512980766520059820 0x3ea15418aa9927ac
//15821377118299441610 0xdb90d2a9f1bb49ca
//15512417228822200185 0xd7472d480398bf79

#6


有 io 操作当然耗时.加上大量的 fseek (如果是非固态硬盘会跳硬盘磁头....巨耗时)
内存够大,一般都采用 空间换时间 的方法.

1) 采用内存映射文件方法进行操作,

2), 采用 一次 fread() 所以数据,---> 处理 ----> 一次 fwrite()所有数据


// -------------------------------------------
记得N久久前实现一数据整理功能.
用边读边处理边写方法     耗时:  吸一根烟时间
一次读入处理一次写方法 耗时:  点一根烟时间

#7


高兴了楼主试试将文件放在RAMDISK上,估计打火机没从兜里掏出来就over了。 关于fseek, fwrite, fread的耗时问题

#8


引用 6 楼 dooX8086 的回复:
有 io 操作当然耗时.加上大量的 fseek (如果是非固态硬盘会跳硬盘磁头....巨耗时)
内存够大,一般都采用 空间换时间 的方法.

1) 采用内存映射文件方法进行操作,

2), 采用 一次 fread() 所以数据,---> 处理 ----> 一次 fwrite()所有数据


// -------------------------------------------
记得N久久前实现一数据整理功能.
用边读边处理边写方法     耗时:  吸一根烟时间
一次读入处理一次写方法 耗时:  点一根烟时间



7个G的数据啊……读入内存不现实啊,还是说把7个G拆成小部分分别处理?

#9


引用 7 楼 zhao4zhong1 的回复:
高兴了楼主试试将文件放在RAMDISK上,估计打火机没从兜里掏出来就over了。 关于fseek, fwrite, fread的耗时问题


多谢多谢,我看看,感觉好高端= =

#10


现在Win64位系统高配的话,内存是多少G来着? 关于fseek, fwrite, fread的耗时问题

#11


提醒楼主:超过2GB的文件好象不能用fseek得改用_fseeki64(Windows)或fseeko64(Linux)了吧。
关于fseek, fwrite, fread的耗时问题

#12


引用 11 楼 zhao4zhong1 的回复:
提醒楼主:超过2GB的文件好象不能用fseek得改用_fseeki64(Windows)或fseeko64(Linux)了吧。
关于fseek, fwrite, fread的耗时问题


我这并没有报错,7个G的文件……

#13


引用 12 楼 kuaitoukid 的回复:
Quote: 引用 11 楼 zhao4zhong1 的回复:

提醒楼主:超过2GB的文件好象不能用fseek得改用_fseeki64(Windows)或fseeko64(Linux)了吧。
关于fseek, fwrite, fread的耗时问题


我这并没有报错,7个G的文件……

那可能是因为你用64位编译环境且在64系统下运行。

#1


数据量很大吗,没完全明白你的意思, 打乱(读取出来在写回去?),生成索引(索引存在哪里),按索引查找(怎么查找),你仔细想想你的逻辑处理上有没有可优化的。

#2


引用 1 楼 a30037338 的回复:
数据量很大吗,没完全明白你的意思, 打乱(读取出来在写回去?),生成索引(索引存在哪里),按索引查找(怎么查找),你仔细想想你的逻辑处理上有没有可优化的。



数据量很大,400万的样本量,是写到拷贝的样本里面,肯定不能直接写到原样本,这样就覆盖了,索引是提前生成好的,每次都要fread这个索引文件来获取fseek的位置

#3


引用 1 楼 a30037338 的回复:
数据量很大吗,没完全明白你的意思, 打乱(读取出来在写回去?),生成索引(索引存在哪里),按索引查找(怎么查找),你仔细想想你的逻辑处理上有没有可优化的。


我是用MATLAB的randperm来生成的索引 = =

#4


仅供参考:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int d[6];
int i,n,a,b,t;
int c,j;
void main() {
    srand(time(NULL));
    printf("shuffle 0..n-1 demo\n");
    for (n=1;n<=5;n++) {/* 测试1~5个元素 */
        printf("_____n=%d_____\n",n);
        j=1;
        for (c=1;c<=n;c++) j=j*c;/* j为n! */
        j*=n*2;
        for (c=1;c<=j;c++) {/* 测试n*2*n!次 */
            for (i=0;i<n;i++) d[i]=i;/* 填写0~n-1 */
            for (i=n;i>0;i--) {/* 打乱0~n-1 */
                a=i-1;b=rand()%i;
                if (a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
            }
            printf("%04d:",c);
            for (i=0;i<n;i++) printf("%d",d[i]);
            printf("\n");
        }
    }
    printf("shuffle 1..n demo\n");
    for (n=1;n<=5;n++) {/* 测试1~5个元素 */
        printf("_____n=%d_____\n",n);
        j=1;
        for (c=1;c<=n;c++) j=j*c;/* j为n! */
        j*=n*2;
        for (c=1;c<=j;c++) {/* 测试n*2*n!次 */
            for (i=1;i<=n;i++) d[i]=i;/* 填写1~n */
            for (i=n;i>1;i--) {/* 打乱1~n */
                a=i;b=rand()%i+1;
                if (a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
            }
            printf("%04d:",c);
            for (i=1;i<=n;i++) printf("%d",d[i]);
            printf("\n");
        }
    }
}

#5


再供参考:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
unsigned long ulrand(void) {
    return (
     (((unsigned long)rand()<<24)&0xFF000000ul)
    |(((unsigned long)rand()<<12)&0x00FFF000ul)
    |(((unsigned long)rand()    )&0x00000FFFul));
}
unsigned __int64 ullrand(void) {
    return (
     (((unsigned __int64)ulrand())<<32)
    | ((unsigned __int64)ulrand()));
}
int i;
unsigned long ul;
unsigned __int64 ull;
void main() {
    srand(time(NULL));
    for (i=0;i<10;i++) {
        ul=ulrand();
        printf("%010lu 0x%08x\n",ul,ul);
    }
    for (i=0;i<10;i++) {
        ull=ullrand();
        printf("%020I64u 0x%016I64x\n",ull,ull);
    }
}
//3971076432 0xecb1d150
//2433428051 0x910b2a53
//1415415336 0x545d8628
//1312330759 0x4e389407
//1845758378 0x6e0409aa
//0008069933 0x007b232d
//4202720757 0xfa806df5
//2669855255 0x9f22c217
//0312068736 0x1299ca80
//2084555989 0x7c3fccd5
//03502077880857307931 0x3099e1472040ab1b
//16884702393146816355 0xea52835e19b43763
//01877364819396611730 0x1a0dbd5b45f34e92
//07839440151924835771 0x6ccb4948756a05bb
//09471412086917299176 0x8371371c820bfbe8
//04411255971577469925 0x3d37edef2f321be5
//13735846279546091130 0xbe9f876a65b7367a
//04512980766520059820 0x3ea15418aa9927ac
//15821377118299441610 0xdb90d2a9f1bb49ca
//15512417228822200185 0xd7472d480398bf79

#6


有 io 操作当然耗时.加上大量的 fseek (如果是非固态硬盘会跳硬盘磁头....巨耗时)
内存够大,一般都采用 空间换时间 的方法.

1) 采用内存映射文件方法进行操作,

2), 采用 一次 fread() 所以数据,---> 处理 ----> 一次 fwrite()所有数据


// -------------------------------------------
记得N久久前实现一数据整理功能.
用边读边处理边写方法     耗时:  吸一根烟时间
一次读入处理一次写方法 耗时:  点一根烟时间

#7


高兴了楼主试试将文件放在RAMDISK上,估计打火机没从兜里掏出来就over了。 关于fseek, fwrite, fread的耗时问题

#8


引用 6 楼 dooX8086 的回复:
有 io 操作当然耗时.加上大量的 fseek (如果是非固态硬盘会跳硬盘磁头....巨耗时)
内存够大,一般都采用 空间换时间 的方法.

1) 采用内存映射文件方法进行操作,

2), 采用 一次 fread() 所以数据,---> 处理 ----> 一次 fwrite()所有数据


// -------------------------------------------
记得N久久前实现一数据整理功能.
用边读边处理边写方法     耗时:  吸一根烟时间
一次读入处理一次写方法 耗时:  点一根烟时间



7个G的数据啊……读入内存不现实啊,还是说把7个G拆成小部分分别处理?

#9


引用 7 楼 zhao4zhong1 的回复:
高兴了楼主试试将文件放在RAMDISK上,估计打火机没从兜里掏出来就over了。 关于fseek, fwrite, fread的耗时问题


多谢多谢,我看看,感觉好高端= =

#10


现在Win64位系统高配的话,内存是多少G来着? 关于fseek, fwrite, fread的耗时问题

#11


提醒楼主:超过2GB的文件好象不能用fseek得改用_fseeki64(Windows)或fseeko64(Linux)了吧。
关于fseek, fwrite, fread的耗时问题

#12


引用 11 楼 zhao4zhong1 的回复:
提醒楼主:超过2GB的文件好象不能用fseek得改用_fseeki64(Windows)或fseeko64(Linux)了吧。
关于fseek, fwrite, fread的耗时问题


我这并没有报错,7个G的文件……

#13


引用 12 楼 kuaitoukid 的回复:
Quote: 引用 11 楼 zhao4zhong1 的回复:

提醒楼主:超过2GB的文件好象不能用fseek得改用_fseeki64(Windows)或fseeko64(Linux)了吧。
关于fseek, fwrite, fread的耗时问题


我这并没有报错,7个G的文件……

那可能是因为你用64位编译环境且在64系统下运行。