怎样提高写文件的速度
情况是这样的:我在写一个从网络接收报文,然后把报文存在一个文件里面的程序。报文发送的间隔达到了几十微秒,时间非常短。
这部分代码如下:
if(*counter==1)
{
if((fd=open("/home/goosefile.txt",O_RDWR|O_CREAT))<0)
{
DBGL("file open failed\n");
exit(1);
}
}
if((file_w=fork())<0)
{
DBGL("fork file operation failed\n");
exit(1);
}
if(file_w>0)
{
waitpid(file_w,NULL,0);
++file_count;
printf("countnum is %lu\n",file_count);//这是计算接收到的报文数量
}
else if(file_w==0)
{
lseek(fd,10,SEEK_END);
if((writefd=write(fd,packet,pkthdr->len))<0)
{
DBGL("file write failed\n");
exit(1);
}
exit(1);
}
文件只在第一个报文到来的时候打开一次,每次来一个报文都开辟一个进程,主进程等待子进程结束,子进程退出。 但是测试结果非常不理想:发10000个报文只能接收到7000个左右,而且如果提高发送速率的话,收到的报文就更少了。
就是说,现在如何提高写文件的速度。
------解决方案--------------------用标准I/O函数,,fprintf,fscanf,fwrite,fread,fopen,fclose,,,这个自带缓冲。
或者如果你非要用write,read读写文件的话,就自己加个缓存,,每4KB或者8KB时一次性写入。这样磁盘I/O效率最高。而用标准I/O函数就不用考虑这个问题了,因为他自带缓冲
还有你不应该使用接收一个报文就fork一下,,fork的开锁是比较大的。。
应该使用单消费者/单生产者的模型或者单生产者/多消费者模型。。一个线程负责接收报文放到公共缓冲区,另一个(或多个)线程负责从公共缓冲中取报文,然后fwrite到文件。 单生产者一般用环形缓冲配合锁实现,,自己搜索下,
------解决方案--------------------网络I/O线程负责收,直接丢到链式队列里,让文件I/O线程去顺序写。
方案1:直接mutex+cond+queue,网络I/O线程只管往queue里丢了就signal唤醒cond,无须判断队列容量,直到撑爆内存core掉为止(可做内存池控制进程内存low-waterline防core,不过会导致丢弃部分报文,也可直接控制队列容量,丢弃报文即可,但不可挂起cond导致阻塞网络I/O),文件I/O就是取了去写,队列空就挂起cond。
方案2:epoll+pipe/socketpair+1字节做文件I/O实践触发, 写pipe失败则丢弃报文即可,或者和上面一样直接控制队列尺寸即可.
------解决方案--------------------楼上都有大的建议,我说一句,就是要接受线程 与 写文件线程分开。 还有如果不知道你写的文件内容以后只是留作记录。为什么不考虑共享缓冲区代替反复写硬盘,把受到的内容放在内存中,退出时统一刷到硬盘。
------解决方案--------------------
------解决方案--------------------内存映射最快, 1G的文件用内存映射可以秒, 普通I/O就慢的要命.
楼主完全可以做内存映射,
1,自己估摸一下最长的报文是max_size.
2,将max_size向上对齐到4倍数得到piece_size.
3,计算一下1G/piece_size等于n条。
以后每次将文件尺寸扩展1G,然后内存映射,以piece_size为偏移最小单位,每次偏移过去将报文复制上去。
64位服务器16G内存,可以每次映射8G,自己看着弄。
需要在文件头部维护一个结构体,存储这个文件当前多少个G了,以及在当前那1G里写了多少piece了。
------解决方案--------------------只是用来持续的写文件,,用内存映射并不会快的,,你这样占的内存也太大了些吧,,,并且把问题复杂化了。
简单问题简单解决,,两线程的单生产者/单消费者+fwrite写文件就行了。
------解决方案--------------------
------解决方案--------------------mmap ?