问题描述
privatevoidFileCopy(ObjectStates){stringhomedir=(string)States;string[]dirs=Directory.GetDirectories(homedir);Common.prgsBarTotal.Maximum=dirs.Length;Common.prgsBarTotal.Value=0;ThreadPool.SetMaxThreads(0,8);foreach(stringdirindirs){string[]files=Directory.GetFiles(dir);do{//thiscodeshouldbetestedfirstThreadPool.GetAvailableThreads(outa,outb);Thread.Sleep(517);ThreadPool.GetMaxThreads(outc,outd);}while(b!=d&&a!=c);iCount=0;Common.prgsBar.Value=0;Common.prgsBar.Maximum=files.Length;MaxCount=files.Length;Common.richTextBox.AppendText("切换文件夹:t"+dir+"n");if(files.Length==0){continue;}foreach(stringfileinfiles){//concretCopy(file);//ThreadPool.RegisterWaitForSingleObject(eventP,newWaitCallback(concretCopy),file,1000,true);ThreadPool.QueueUserWorkItem(newWaitCallback(concretCopy),file);}Common.prgsBarTotal.Value+=Common.prgsBarTotal.Step;//eventX.Reset();eventX.WaitOne();eventX.Reset();GC.Collect();}/*stringdir=(string)States;string[]files=Directory.GetFiles(dir);eventX.Reset();iCount=0;Common.prgsBar.Value=0;Common.prgsBar.Maximum=files.Length;MaxCount=files.Length;foreach(stringfileinfiles){ThreadPool.SetMaxThreads(1,1);ThreadPool.QueueUserWorkItem(newWaitCallback(concretCopy),file);}Common.prgsBarTotal.Value+=Common.prgsBarTotal.Step;eventX.WaitOne();eventX.Reset();GC.Collect();string[]dirs=Directory.GetDirectories(dir);foreach(stringdindirs){FileCopy(d);Common.richTextBox.AppendText("切换文件夹n");}**/}privatevoidconcretCopy(ObjectState){//inta=Common.prgsBar.Value;stringfile=(string)State;lock(Common.o){Common.prgsBar.Value+=Common.prgsBar.Step;Common.richTextBox.AppendText(DateTime.Now+"t"+Thread.CurrentThread.ManagedThreadId+"t"+file+"thavecheckedn");}if(file.ToLower().EndsWith(".json".ToLower())){//todo:打开文件,检验其中的内容,是不是我要的uri,如果是的话,关闭//这个文件流,把这个文件和对应的csv文件,复制到目标文件夹。stringline=readFile(file);stringuri=getURI(line);stringtar;if(checkURI(uri,outtar)){list.Clear();Common.getJSON(line,list,1);FileInfofileinfo=newFileInfo(file);stringdes=Common.outputDir+"\"+tar.Replace("/","").Replace(":","");Common.getValueByName("filename",list,refwebvalues);Common.getValueByName("csvname",list,refcsvnames);Common.getValueByName("language",list,reflanguage);stringroot=fileinfo.DirectoryName;foreach(stringwebvalueinwebvalues){if(File.Exists(fileinfo.DirectoryName+"\"+webvalue)){File.Copy(fileinfo.DirectoryName+"\"+webvalue,des+"\"+webvalue,true);}else{log.Log("**********************=========newweboccur========********************");log.Log(DateTime.Now+"t"+file);log.Log(DateTime.Now+"t"+fileinfo.DirectoryName+"\"+webvalue+"notexistn");}}foreach(stringcsvnameincsvnames){if(File.Exists(fileinfo.DirectoryName+"\"+csvname)){File.Copy(fileinfo.DirectoryName+"\"+csvname,des+"\"+csvname,true);}else{log.Log("**********************==========newcsvoccur============********************");log.Log(DateTime.Now+"t"+file);log.Log(DateTime.Now+"t"+fileinfo.DirectoryName+"\"+csvname+"notexistn");}}File.Copy(file,des+"\"+fileinfo.Name,true);}}Interlocked.Increment(refiCount);if(iCount>=MaxCount){eventX.Set();}}
调用的顺序就是从FileCopy到concreteCopy,为什么,当在含有50w个文件夹中,执行的时候,会越来越慢,本人菜鸟,求教育,求指点。
解决方案
解决方案二:
你看看你的内存是不是占用很多,内存得不到及时释放频繁调用GC.Collect();看看是不是有可以复用的方法,比如开缓存等,另外线程不要太多
解决方案三:
内存的情况是这样的,30+,60+,110+,150+这样循环着跳,另外,没有开太多线程,就开了一个线程池,没有别的线程了,list也每次都清理了,不是递增的。实在想不明白了
解决方案四:
引用1楼bdmh的回复:
你看看你的内存是不是占用很多,内存得不到及时释放频繁调用GC.Collect();看看是不是有可以复用的方法,比如开缓存等,另外线程不要太多
内存的情况是这样的,30+,60+,110+,150+这样循环着跳,另外,没有开太多线程,就开了一个线程池,没有别的线程了,list也每次都清理了,不是递增的。我实在想不明白了
解决方案五:
程序比较乱,有些代码也不知道是干什么的,随便说几点:在工作程序中,访问UI组件,使用BeginInvoke,不要同步阻塞地去Invoke,也不要有不必要的lock语句。否则你的线程也没有多大意义。你的程序“看上去越跑越慢”是正常的。因为你的更新进度条的语句是在线程执行程序的“开头”而不是“结尾”。ThreadPool会自动根据最合理的情况来延迟、批量启动线程,不会一下子启动所有线程。如果一下子并发执行所有线程(假设可能的话),你会一下子就看到进度条跑到100%了,然后就是一直在等待。而现在ThreadPool只会逐步启动批量线程,所以你看到的不是一下子跑到100%。如果你把更新进度条的语句挪到concretCopy方法的最后去,你就不会被一开始的那种假想所迷惑了。不用调用GC。它不会让你的程序变快的。你这里并没有“大规模申请内存、然后一直不释放,最后一瞬间才突然释放几百兆内存”的情况。你的程序的concretCopy执行完,局部变量就会自动被GC释放。用代码调用GC通常只会让程序更慢(但是影响很小),总之不会更快的。
解决方案六:
引用4楼sp1234的回复:
程序比较乱,有些代码也不知道是干什么的,随便说几点:在工作程序中,访问UI组件,使用BeginInvoke,不要同步阻塞地去Invoke,也不要有不必要的lock语句。否则你的线程也没有多大意义。你的程序“看上去越跑越慢”是正常的。因为你的更新进度条的语句是在线程执行程序的“开头”而不是“结尾”。ThreadPool会自动根据最合理的情况来延迟、批量启动线程,不会一下子启动所有线程。如果一下子并发执行所有线程(假设可能的话),你会一下子就看到进度条跑到100%了,然后就是一直在等待。而现在ThreadPool只会逐步启动批量线程,所以你看到的不是一下子跑到100%。如果你把更新进度条的语句挪到concretCopy方法的最后去,你就不会被一开始的那种假想所迷惑了。不用调用GC。它不会让你的程序变快的。你这里并没有“大规模申请内存、然后一直不释放,最后一瞬间才突然释放几百兆内存”的情况。你的程序的concretCopy执行完,局部变量就会自动被GC释放。用代码调用GC通常只会让程序更慢(但是影响很小),总之不会更快的。
进度条不是我关注的重点,现在的问题就是,在50万个文件的文件夹下跑的话,跑过一天以后,程序会很慢,但是刚开始的时候很快的,还有一个问题就是,内存是30+、60+、80+、112、150,这样循环的跳,不知道这个能说明什么问题。list是clear的,并没有递增,Json是结构体,并不是类
解决方案七:
用线程池执行copy没什么意义磁盘比起CPU是很慢的你CPU开那么多线程,似乎可以跑的飞快,但是其实到磁盘那里,还是得一点一点的写入文件你不如改成顺序执行,而不是并发执行
解决方案八:
至于说你的do{}while循环,你又要设置ThreadPool.SetMaxThreads(0,8),又要循环等待人家.netframework一个线程都不占用的时候才继续执行for循环。是不是你想“控制”的太多了。删除这两块代码,会更好。不要去设置系统线程池大小(虽然在.net4.0下,即使你设置了,可能也还是会使用1000~60000多个,而不是你设置的8)。也不要写下面的循环语句。线程池会自动优化,不是等到b!=d&&a!=c条件才可以继续跑的。总的来说,线程虽然会让你的程序的每一个concretCopy看起来变慢,比如说并发3个线程是1秒做完一个任务,并发20个线程时是10秒做完一个任务,并发50个线程时是30秒做完一个任务,但是总的执行时间反而缩短了。并发时,每一个任务的执行时间可能变慢到原来的200倍,但是总的执行时间却缩短到原来的10分之一。所以如果你想一下子就看到每一个任务的执行时间没有缩短,就不要并发。并发必定是让每一个任务都牺牲速度,来获取总的任务更快执行完毕的。
解决方案九:
如果你想一下子就看到每一个任务的执行时间没有缩短-->如果你想一下子就看到每一个任务的执行时间没有延长当有一堆不同类型的操作时,并发确实可以避免CPU空闲时别的任务也得不到执行。但是当你有一堆完全一样的任务,那么并发时你肯定看到每一个任务的执行时间都大大延长了,只不过总的完成时间缩短了而已。
解决方案十:
引用6楼Z65443344的回复:
用线程池执行copy没什么意义磁盘比起CPU是很慢的你CPU开那么多线程,似乎可以跑的飞快,但是其实到磁盘那里,还是得一点一点的写入文件你不如改成顺序执行,而不是并发执行
是这样的,您说的顺序执行的我也试了,到最后界面都卡顿了,但是在程序刚打开的一瞬间,刷刷的,那速度,为什么后来就惨不忍睹了。
解决方案十一:
因为你用了Common.richTextBox.AppendText控件里内容多了之后,刷新必然变慢,你只往里不断添加文本,而从来不清除过期数据
解决方案十二:
引用8楼sp1234的回复:
如果你想一下子就看到每一个任务的执行时间没有缩短-->如果你想一下子就看到每一个任务的执行时间没有延长当有一堆不同类型的操作时,并发确实可以避免CPU空闲时别的任务也得不到执行。但是当你有一堆完全一样的任务,那么并发时你肯定看到每一个任务的执行时间都大大延长了,只不过总的完成时间缩短了而已。
其实我也没有针对单个任务,快慢的比较是说,在刚开始执行程序的时候,和执行了很长一段时间以后,这两个时间点进行比较,相同的代码为什么随着时间的推移,越来越慢呢
解决方案十三:
引用10楼Z65443344的回复:
因为你用了Common.richTextBox.AppendText控件里内容多了之后,刷新必然变慢,你只往里不断添加文本,而从来不清除过期数据
这个有道理,我去试试:),thx
解决方案十四:
把所有结果都放到richTextBox里显示不仅内存越占越多,而且随着内容增多,刷新也会越来越慢毕竟它是带自动滚动条的,要计算里面的行数,要根据行数来计算滚动条拖块的高度,要绘制文字,绘制滚动条
解决方案十五:
引用11楼n2202666的回复:
其实我也没有针对单个任务,快慢的比较是说,在刚开始执行程序的时候,和执行了很长一段时间以后,这两个时间点进行比较,相同的代码为什么随着时间的推移,越来越慢呢
你应该等到线程数达到最大值并且不再增加时,再开始观察执行速度。
其他方案:
引用12楼n2202666的回复:
Quote: 引用10楼Z65443344的回复:
因为你用了Common.richTextBox.AppendText控件里内容多了之后,刷新必然变慢,你只往里不断添加文本,而从来不清除过期数据这个有道理,我去试试:),thx
你的FileCopy本身就不应该放在主线程里执行,它受UI刷新速度越来越慢的影响。你的程序中有直接卡死在UI控件上的代码,而且还有lock语句(语句中需要等待界面UI同步处理结束才能继续执行)。
其他方案:
引用13楼Z65443344的回复:
把所有结果都放到richTextBox里显示不仅内存越占越多,而且随着内容增多,刷新也会越来越慢毕竟它是带自动滚动条的,要计算里面的行数,要根据行数来计算滚动条拖块的高度,要绘制文字,绘制滚动条
大神,我爱你,我们交个朋友吧,clear以后,我发现我的世界瞬间就干净了,有你真好,QQ527573638,真心求交友
其他方案:
如果没有“阻塞式”的代码(访问UI控件、lock、无端地搞循环语句,这些都是阻塞自己的),即使你往主线程的UI上去Append一些内容,如果你的机器的CPU不是持续跑满95%以上的,那么你的多线程处理程序的进度也应该是保持平稳的。应该把跨线程阻塞的语句尽可能全都改掉。
其他方案:
引用17楼sp1234的回复:
如果没有“阻塞式”的代码(访问UI控件、lock、无端地搞循环语句,这些都是阻塞自己的),即使你往主线程的UI上去Append一些内容,如果你的机器的CPU不是持续跑满95%以上的,那么你的多线程处理程序的进度也应该是保持平稳的。应该把跨线程阻塞的语句尽可能全都改掉。
恩,我理解你的意思,你对多线程学的很透彻,可能是我没有把代码全贴出来,那些阻塞的不能去掉,那是逻辑的代码,去掉以后,整个程序就坏了,,谢谢你的帮助