多线程拷贝大文件的问题。

时间:2022-06-24 10:07:24
本人菜鸟实在想不通。
 就如迅雷那样,先建立一个 和源文件大小的 目标文件 ,然后开设多个现成 分块读取分块写入,功能是实现了,但是当我拷贝1个G大小的文件 两个线程比一个线程 多用了4倍时间,下面贴上代码,求解啊:

CEvent eventObj(FALSE,TRUE);
int g_maxnum; //当前线程结束情况
typedef struct TAG_INFO  
{  
CString fromfile;                 //源地址  
CString tofile;                  //目的地址  
int num;                      //启动的第i-1个进程  
int maxnum; //最大线程数量
}info;

void CThreadCopyDlg::OnCopy() 
{
// TODO: Add your control notification handler code here
int maxnum = GetDlgItemInt(IDC_TNUM); //获取要开启的线程数
if(filename.IsEmpty())
return;
if(pathname.IsEmpty())
return;
preadfile=new CFile;
if (preadfile==NULL)
return;
preadfile->Open(pathname,CFile::modeRead);

filelen=preadfile->GetLength();

//创建同样大小的目标文件
HANDLE hFile;  
    HANDLE hMapFile;  
    hFile = CreateFile(  
        fullname,  
        GENERIC_WRITE | GENERIC_READ,  
        FILE_SHARE_READ,  
        NULL,  
        CREATE_ALWAYS,  
        FILE_ATTRIBUTE_NORMAL,  
        NULL  
        );  
    if( hFile == INVALID_HANDLE_VALUE )  
    {  
        OutputDebugString(_T("CreateFile fail!/r/n"));  
        return ;  
    }  
    hMapFile = CreateFileMapping(  
        hFile,  
        NULL,  
        PAGE_READWRITE,  
        0,  
        filelen,   
        NULL  
        );  
    if( hMapFile == NULL )  
    {  
        CloseHandle( hFile );  
        return ;      
    }  
    CloseHandle( hMapFile );  
    CloseHandle( hFile ); 
//创建结束

preadfile->Close();
delete preadfile;
preadfile=NULL;

info info1[10];
for (int i=0;i<maxnum;i++)
{
//mutexWriteE.Lock();
info1[i].num = i;
info1[i].tofile = fullname;
info1[i].fromfile = pathname;
info1[i].maxnum = maxnum;
AfxBeginThread(threadDL,&info1[i],THREAD_PRIORITY_NORMAL);
}
g_maxnum = maxnum;

eventObj.Lock();        //主线程处于等待状态  
eventObj.ResetEvent();

AfxMessageBox("拷贝完成");
}

UINT  threadDL(LPVOID  param) {
info info2 = *((info*)param);
CString fromfile;
CString tofile;
int num = info2.num;
int maxmun = info2.maxnum;
long filelen;

fromfile = info2.fromfile;
tofile = info2.tofile;

CFile* pwritefile;
CFile* preadfile;
//preadfile->Open(fromfile,CFile::modeRead);//open the file%

preadfile=new CFile(fromfile,CFile::modeRead | CFile::shareDenyNone);
if (preadfile==NULL)
return 0;

pwritefile=new CFile(tofile,CFile::modeWrite | CFile::shareDenyNone);//共享写

if (pwritefile==NULL)
{
delete preadfile;
preadfile=NULL;
return 0;
}

filelen=preadfile->GetLength();//get the length of the file

char temp[1024]; 
ZeroMemory(temp,1024);

//将文件指针分别设置在每个线程要读和写的位置  
preadfile->Seek(filelen*num/maxmun,SEEK_SET);
pwritefile->Seek(filelen*num/maxmun,SEEK_SET);
//long onepercent = filelen/maxmun/100;
long position=0;
while(position<filelen/maxmun)
{
int retbytes=preadfile->Read(temp,1024);
pwritefile->Write(temp,retbytes);
position = position + retbytes;
}
preadfile->Close();
pwritefile->Close();
delete preadfile;
preadfile=NULL;
delete pwritefile;
pwritefile=NULL;
g_maxnum--;
if (g_maxnum == 0)
{
eventObj.SetEvent();

return 0;
}

求解脱啊。到底哪里需要优化

8 个解决方案

#1


就算代码没问题,这个根据环境不同也是存在的,瓶颈主要在IO,另线程之间的切换也是消耗时间的。事实上,迅雷开多线程的目的是为了解决接收的效率,而正常情况下写数据那么一点点时间影像微乎其微,所以不必在意

#2


你开多线程写大文件一点用没有。因为硬盘里面就一个磁头,所以在同一时间只有可能进行一次写入操作。
而IO的时间主要花费在硬盘磁头寻址上,本来写一个文件地址都是连续的磁头寻址一次就可以写完。
而两个线程写磁头需要在线程切换时从新寻址。所以时间就多了。

#3


多个线程写并不一定能提升,多线程只是可以多做几个事情

#4


引用 2 楼 yaoyi098 的回复:
你开多线程写大文件一点用没有。因为硬盘里面就一个磁头,所以在同一时间只有可能进行一次写入操作。
而IO的时间主要花费在硬盘磁头寻址上,本来写一个文件地址都是连续的磁头寻址一次就可以写完。
而两个线程写磁头需要在线程切换时从新寻址。所以时间就多了。

不是吧 那这样说来,多线程写大文件没有一点优势了啊?

#5


那在写大文件时 怎么才能提高速度啊?

#6


引用 5 楼 u012479410 的回复:
那在写大文件时 怎么才能提高速度啊?


主流硬盘7200转写入速度峰值大概在100MB/s左右,连续写入的话可能也就70-90 这是硬件瓶颈,只能通过硬件提升来提升,例如RAID。

#7


一个文件储存在硬盘上,一般都在一段连续的硬盘空间,硬盘读取数据是以一簇一簇,整个扇区方式进行读取,一个线程复制文件,硬盘的磁头只在读与写的两个区域进行转化。两个线程进行复制,硬盘的磁头在读与写4个区域进行跳转,跳转的还包括寻道时间,所消耗时间基本上是2次方倍。差不多4倍时间!想加快速度,只能在减少跳转时间去考虑,所以加大buffer的空间大小,会加快多线程复制的时间。

#8


谢谢大家了,已经明白到底这么回事了

#1


就算代码没问题,这个根据环境不同也是存在的,瓶颈主要在IO,另线程之间的切换也是消耗时间的。事实上,迅雷开多线程的目的是为了解决接收的效率,而正常情况下写数据那么一点点时间影像微乎其微,所以不必在意

#2


你开多线程写大文件一点用没有。因为硬盘里面就一个磁头,所以在同一时间只有可能进行一次写入操作。
而IO的时间主要花费在硬盘磁头寻址上,本来写一个文件地址都是连续的磁头寻址一次就可以写完。
而两个线程写磁头需要在线程切换时从新寻址。所以时间就多了。

#3


多个线程写并不一定能提升,多线程只是可以多做几个事情

#4


引用 2 楼 yaoyi098 的回复:
你开多线程写大文件一点用没有。因为硬盘里面就一个磁头,所以在同一时间只有可能进行一次写入操作。
而IO的时间主要花费在硬盘磁头寻址上,本来写一个文件地址都是连续的磁头寻址一次就可以写完。
而两个线程写磁头需要在线程切换时从新寻址。所以时间就多了。

不是吧 那这样说来,多线程写大文件没有一点优势了啊?

#5


那在写大文件时 怎么才能提高速度啊?

#6


引用 5 楼 u012479410 的回复:
那在写大文件时 怎么才能提高速度啊?


主流硬盘7200转写入速度峰值大概在100MB/s左右,连续写入的话可能也就70-90 这是硬件瓶颈,只能通过硬件提升来提升,例如RAID。

#7


一个文件储存在硬盘上,一般都在一段连续的硬盘空间,硬盘读取数据是以一簇一簇,整个扇区方式进行读取,一个线程复制文件,硬盘的磁头只在读与写的两个区域进行转化。两个线程进行复制,硬盘的磁头在读与写4个区域进行跳转,跳转的还包括寻道时间,所消耗时间基本上是2次方倍。差不多4倍时间!想加快速度,只能在减少跳转时间去考虑,所以加大buffer的空间大小,会加快多线程复制的时间。

#8


谢谢大家了,已经明白到底这么回事了