使用Windows API在c中异步操作:使用哪种方法以及为什么我的代码
我有一个C应用程序,它产生大量的输出,速度是至关重要的.该程序基本上是一个大型(8-12GB)二进制输入文件的循环,必须按顺序读取.在每次迭代中,处理读取的字节并生成输出并将其写入多个文件,但不会同时写入多个文件.因此,如果您处于生成输出的位置,并且有4个输出文件,则写入文件0或1或2或3.在迭代结束时,我现在使用fwrite()编写输出,从而等待写操作完成.输出操作总数很大,每个文件最多400万,文件输出大小从100mb到3.5GB不等.该程序在基本的多核处理器上运行.
我想在一个单独的线程中写输出,我知道这可以完成 >异步I / O. 我有两类问题,即概念和特定代码. 概念性问题 什么是最好的方法.请注意,应用程序应该可以移植到Linux,但是,我不知道这对于我选择的1-3是多么重要,因为我会编写一个关于任何内核/ API特定的包装器.对我来说,最重要的标准是速度.我已经读过,选项1不太可能提高程序的性能,并且内核在任何情况下都会为i / o操作创建新的线程,所以为什么不立即使用选项(2),看起来好像很有用更容易编程(因为我没有使用选项(1)成功,请参阅下面的代码问题). 请注意,我阅读了https://stackoverflow.com/questions/3689759/how-can-i-run-a-specific-function-of-thread-asynchronously-in-c-c,但是根据应用程序的性质,我没有看到使用内容的动机.所以我希望有人能给我一些建议,在我的情况下最好.同样来自Johnson M. Hart的“Windows系统编程”一书,我知道建议使用线程,主要是因为它的简单性.但是,它也会最快吗? 代码问题 这个问题涉及到目前为止我为使异步I / O工作所做的尝试.我知道它是一个很大的代码,所以它不容易调查.无论如何,我真的很感激任何尝试. 为了减少执行时间,我尝试使用带有重叠结构的FILE_FLAGGED_OVERLAP的CreateFile()使用WINAPI通过新线程编写输出.我已经创建了一个示例程序,我试图让它工作.但是,我遇到了两个问题: >当我删除已存在的文件时,文件仅以重叠模式打开(我尝试在不同模式下使用CreateFile(CREATE_ALWAYS,CREATE_NEW,OPEN_EXISTING),但这没有用). 请注意,程序在执行路径中创建一个大约120mb的文件.另请注意,打印报表“不行”是不可取的,我希望看到“可以在后台工作”出现在我的屏幕上……这里出了什么问题? #include <windows.h> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #define ASYNC // remove this definition to run synchronously (i.e. using fwrite) #ifdef ASYNC struct _OVERLAPPED *pOverlapped; HANDLE *pEventH; HANDLE *pFile; #else FILE *pFile; #endif #define DIM_X 100 #define DIM_Y 150000 #define _PRINTERROR(msgs) {printf("file: %s,line: %d,%s",__FILE__,__LINE__,msgs); fflush(stdout); return 0;} #define _PRINTF(msgs) {printf(msgs); fflush(stdout);} #define _START_TIMER time_t time1,time2; clock_t clock1; time(&time1); printf("start time: %s",ctime(&time1)); fflush(stdout); #define _END_TIMER time(&time2); clock1 = clock(); printf("end time: %s",ctime(&time2)); printf("elapsed processor time: %.2fn",(((float)clock1)/CLOCKS_PER_SEC)); fflush(stdout); double aio_dat[DIM_Y] = {0}; double do_compute(double A,double B,int arr_len); int main() { _START_TIMER; const char *pName = "test1.bin"; DWORD dwBytesToWrite; BOOL bErrorFlag = FALSE; int j=0; int i=0; int fOverlapped=0; #ifdef ASYNC // create / open the file pFile=CreateFile(pName,GENERIC_WRITE,// open for writing 0,// share write access NULL,// default security CREATE_ALWAYS,// create new/overwrite existing FILE_FLAG_OVERLAPPED,// | FILE_FLAG_NO_BUFFERING,// overlapped file NULL); // no attr. template // check whether file opening was ok if(pFile==INVALID_HANDLE_VALUE){ printf("%xn",GetLastError()); _PRINTERROR("file not opened properlyn"); } // make the overlapped structure pOverlapped = calloc(1,sizeof(struct _OVERLAPPED)); pOverlapped->Offset = 0; pOverlapped->OffsetHigh = 0; // put event handle in overlapped structure if(!(pOverlapped->hEvent = CreateEvent(NULL,TRUE,FALSE,NULL))){ printf("%xn",GetLastError()); _PRINTERROR("error in createeventn"); } #else pFile = fopen(pName,"wb"); #endif // create some output for(j=0;j<DIM_Y;j++){ aio_dat[j] = do_compute(i,j,DIM_X); } // determine how many bytes should be written dwBytesToWrite = (DWORD)sizeof(aio_dat); for(i=0;i<DIM_X;i++){ // do this DIM_X times #ifdef ASYNC //if(i>0){ //SetFilePointer(pFile,dwBytesToWrite,NULL,FILE_CURRENT); //if(!(SetEndOfFile(pFile))){ // printf("%in",pFile); // _PRINTERROR("error in set end of filen"); //} //SetFilePointer(pFile,-dwBytesToWrite,FILE_CURRENT); //} // write the bytes if(!(bErrorFlag = WriteFile(pFile,aio_dat,pOverlapped))){ // check whether io pending or some other error if(GetLastError()!=ERROR_IO_PENDING){ printf("lasterror: %xn",GetLastError()); _PRINTERROR("error while writing filen"); } else{ fOverlapped=1; } } else{ // if you get here output got immediately written; bad! fOverlapped=0; } if(fOverlapped){ // do background,this msgs is what I want to see for(j=0;j<DIM_Y;j++){ aio_dat[j] = do_compute(i,DIM_X); } for(j=0;j<DIM_Y;j++){ aio_dat[j] = do_compute(i,DIM_X); } _PRINTF("can do work in backgroundn"); } else{ // not overlapped,this message is bad _PRINTF("not okn"); } // wait to continue if((WaitForSingleObject(pOverlapped->hEvent,INFINITE))!=WAIT_OBJECT_0){ _PRINTERROR("waiting did not succeedn"); } // reset event structure if(!(ResetEvent(pOverlapped->hEvent))){ printf("%xn",GetLastError()); _PRINTERROR("error in reseteventn"); } pOverlapped->Offset+=dwBytesToWrite; #else fwrite(aio_dat,sizeof(double),DIM_Y,pFile); for(j=0;j<DIM_Y;j++){ aio_dat[j] = do_compute(i,DIM_X); } for(j=0;j<DIM_Y;j++){ aio_dat[j] = do_compute(i,DIM_X); } #endif } #ifdef ASYNC CloseHandle(pFile); free(pOverlapped); #else fclose(pFile); #endif _END_TIMER; return 1; } double do_compute(double A,int arr_len) { int i; double res = 0; double *xA = malloc(arr_len * sizeof(double)); double *xB = malloc(arr_len * sizeof(double)); if ( !xA || !xB ) abort(); for (i = 0; i < arr_len; i++) { xA[i] = sin(A); xB[i] = cos(B); res = res + xA[i]*xA[i]; } free(xA); free(xB); return res; } 有用的链接 > http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011/compiler_c/cref_cls/common/cppref_asynchioC_aio_read_write_eg.htm 我知道这是一个很大的问题,我想提前感谢所有人,他们在阅读它时遇到了麻烦,甚至可能会做出回应!
您应该能够使用OVERLAPPED结构使其工作.
您处于正确的轨道:系统阻止您异步写入,因为每个WriteFile都会扩展文件的大小.但是,您正在进行错误的文件大小扩展.简单地调用SetFileSize实际上不会在MFT中保留空间.使用SetFileValidData函数.这将为您的文件分配集群(请注意它们将包含磁盘所具有的任何垃圾),您应该能够并行执行WriteFile和您的计算. 我会远离FILE_FLAG_NO_BUFFERING.我认为你的并行性表现更好吗?不要阻止缓存执行其工作. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |