我有一个简单的程序,只有一个程序。
Procedure TForm1.btnKeywrdTransClick(Sender: TObject);
Var
i, ii : integer;
ch_word, zword, uy_word: widestring;
Begin
TntListBox1.items.LoadFromFile('d:\new folder\chh.txt'); //Chinese
TntListBox2.items.LoadFromFile('d:\new folder\uyy.txt'); //Uyword
TntListBox4.items.LoadFromFile(Edit3.text); //list of poi files
For I := 0 To TntListBox4.items.Count - 1 do
Begin
TntListBox3.items.LoadFromFile(TntListBox4.Items[i]);
zword := tntlistbox3.Items.Text; //Poi
For ii := 0 To TntListBox1.Items.count - 1 Do
Begin
loopz;
ch_word := tntlistbox1.Items[ii];
uy_word := ' ' + TntListBox2.items[ii] + ' ';
zword := wideFastReplace(zword, ch_word, uy_word, [rfReplaceAll]); //fastest, and better for large text
End;
TntListBox3.Items.text := zword;
TntListBox3.items.SaveToFile(TntListBox4.Items[i]);
end;
end;
现在我的新计算机有4个核心,正在使这个程序多线程会让它运行得更快(如果我使用4个线程,每个核心一个线程)? 我没有多线程的经验,我需要你的帮助 感谢。
ps:这是Loopz程序
Procedure loopz;
Var
msg : tmsg;
Begin
While PeekMessage(Msg, 0, 0, 0, pm_Remove) Do
Begin
If Msg.Message = wm_Quit Then Halt(Msg.WParam);
TranslateMessage(Msg);
DispatchMessage(Msg);
End;
End;
更新1: 从答案,我要做
1 - 使用分析器查找最耗时的代码
2 - 尝试尽可能消除与gui相关的事情
3 - 使用线程。
我会报告回来。谢谢大家。
答案 0 :(得分:14)
首先让算法尽可能有效,因为它当前的化身:停止使用TListBox来存储你的数据!!! (抱歉叫喊)用TStringList替换它们你会获得巨大性能提升。这是任何方式都需要的第一步,因为你不能使用来自多个线程的GUI对象(实际上你只能从“主”线程中使用它们)。当您将TListBox更改为TStringList 时,请为变量指定有意义的名称。我不知道这里有多少人发现你在ListBox4中存储了一个文件名列表,在ListBox3中加载每个文件,使用ListBox1作为“关键字列表”,将ListBox2作为“值列表”...真的,这是一个很大的混乱!以下是TStringList和专有名称的外观:
Procedure TForm1.btnKeywrdTransClick(Sender: TObject);
Var
i, ii : integer;
ch_word, zword, uy_word: widestring;
PoiFilesList:TStringList; // This is the list of files that need work
PoiFile:TStringList; // This is the file I'm working on right now
KeywordList, ValueList:TStringList; // I'll replace all keywords with corresponding values
Begin
PoiFilesList := TStringList.Create;
PoiFile := TStringList.Create;
KeywordList := TStringList.Create;
ValueList := TStringList.Create;
try
PoiFilesList.LoadFromFile(Edit3.text); //list of poi files
KeywordList.LoadFromFile('d:\new folder\chh.txt'); //Chinese
ValueList.LoadFromFile('d:\new folder\uyy.txt'); //Uyword
For I := 0 To PoiFilesList.Count - 1 do
Begin
PoiFile.LoadFromFile(PoiFilesList[i]);
zword := PoiFile.Text; //Poi
For ii := 0 To KeywordList.count - 1 Do
Begin
ch_word := KeywordList[ii];
uy_word := ' ' + ValueList[ii] + ' ';
zword := wideFastReplace(zword, ch_word, uy_word, [rfReplaceAll]);
End;
PoiFile.text := zword;
PoiFile.SaveToFile(PoiFilesList[i]);
end;
finally
PoiFilesList.Free;
PoiFile.Free;
KeywordList.Free;
ValueList.Free;
end;
end;
如果你现在看一下代码,它显然是做什么的,而且很明显如何多线程 - 它。你有一个包含文件名的文本文件。您打开这些文件中的每一个,并用相应的值替换所有关键字。您将文件保存回磁盘。这很简单!将KeywordList和ValueList加载到内存中一次,将文件列表拆分为4个较小的列表,启动4个线程,每个线程使用自己的较小文件列表。
我不想编写代码的整个多线程变体,因为如果我自己编写它,你可能不会理解它是如何工作的。如果遇到麻烦,给它一个机会并寻求帮助。
答案 1 :(得分:4)
首先,您应该对代码进行概要分析,以查看从TntListBox读取是否会降低您的速度或者是否为WideFastReplace。但即使在此之前,删除'loopz'调用 - 它会让你最慢!你为什么要在这个循环中处理消息?
要找到瓶颈,只需将循环计时两次,但第二次注释掉WideFastReplace调用。 (并确保您只计时循环,而不是TntListBox3的赋值或保存到文件或从文件加载。)
当你知道什么在减慢你的速度时,请回报......
BTW,并行调用WideFastReplace几乎是不可能的,因为它始终在同一个源上运行。我没有看到任何有效的代码并行化方法。可能的并行化方法:
当然,如果WideFastReplace不是代码的耗时部分,那么这样做是没有意义的。首先进行分析!
答案 2 :(得分:2)
看起来你正在与GUI元素接口。
99%的GUI代码必须从一个且只有一个线程接口。
如果您重构代码以在一系列线程中执行文本替换,在它们之间划分文本,然后让GUI线程将其放入列表框中,则可以提高性能。
请注意,创建和同步线程并不便宜。除非您有数千个条目要处理,否则您可能会通过添加线程来减慢您的程序。
答案 3 :(得分:1)
通过仅使用一个线程来完成整个过程,您将获得相当大的改进。有了这个,您可以完全省略loopz
电话。
请注意,您应该使用例程中的本地TWideStringList实例替换TntListbox。
如果您对多线程有所了解,可以将工作拆分为多个线程。例如,可以通过在多个(例如3-4个)列表中拆分poi文件列表(listbox4)来完成此操作,每个线程一个。
答案 4 :(得分:1)
可以并行运行的操作受益于多任务处理 - 那些必须一个接一个地运行的操作不能。操作越大,效益越大。在您的过程中,您可以并行化文件加载(虽然我猜它们没有那么多元素)并且您可以并行化具有多个线程的替换操作,每个线程在不同的列表元素上运行。它的运行速度取决于文件大小。 我猜你在使用GUI元素存储数据而不是直接在内存结构上工作时有更多的速度,因为这意味着经常重新绘制控件,这是一项昂贵的操作。
答案 5 :(得分:-1)
这是你的答案
1.如果可以,请不要等到用户单击以对操作做出反应。像在formcreate之前那样做
把它们放入包装对象中
在线程下运行它;完成后,将其标记为可以使用
当用户单击该操作时,请检查标记。如果没有完成
然后做一个循环并等待
btnKeywrdTrans.Enabled := False;
while not wrapper.done do
begin
Sleep(500);
Application.Processmessages;
end;
..... your further logic
btnKeywrdTrans.Enabled := True;
干杯 范