我需要实现以下功能,如何使用多线程实现呢? ( 积分: 200 )

  • 主题发起人 主题发起人 lfpsoft
  • 开始时间 开始时间
L

lfpsoft

Unregistered / Unconfirmed
GUEST, unregistred user!
在文本文件里有10多万的邮件地址记录,但有很多重复的,需要去重复的的。
我用了以下的线程来实现,但速度还是很慢,没有用过多线程,请这里的高手帮帮忙啊!
unit MyThread;
interface
uses
Classes,Controls,SysUtils,Forms;
type
TMyThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute;
override;
end;

implementation
uses MainUnit;
{ Important: Methods and properties of objects in visual components can only be
used in a method called using Synchronize, for example,
Synchronize(UpdateCaption);
and UpdateCaption could look like,
procedure TMyThread.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end;
}
{ TMyThread }
procedure TMyThread.Execute;
var
AList:TStrings;
npos,i:Integer;
begin
{ Place thread code here }
AList := TStringList.Create ;
try
MainForm.Cursor := crHourGlass;
AList.Assign(MainForm.lbIDList.Items);
MainForm.lbIDList.Items.Clear ;
for i:=0 to AList.Count-1do
begin
if Terminated then
break;
MainForm.ProgressBar.Position := i;
nPos := MainForm.lbIDList.Items.IndexOf(AList);
//
if nPos <0 then
begin
MainForm.lbIDList.Items.Add(AList);
MainForm.lbIDList.ItemIndex := MainForm.lbIDList.Count;
end;
end;

finally
MainForm.Cursor := crDefault;
AList.Free ;
end;
end;

end.
 
在文本文件里有10多万的邮件地址记录,但有很多重复的,需要去重复的的。
我用了以下的线程来实现,但速度还是很慢,没有用过多线程,请这里的高手帮帮忙啊!
unit MyThread;
interface
uses
Classes,Controls,SysUtils,Forms;
type
TMyThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute;
override;
end;

implementation
uses MainUnit;
{ Important: Methods and properties of objects in visual components can only be
used in a method called using Synchronize, for example,
Synchronize(UpdateCaption);
and UpdateCaption could look like,
procedure TMyThread.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end;
}
{ TMyThread }
procedure TMyThread.Execute;
var
AList:TStrings;
npos,i:Integer;
begin
{ Place thread code here }
AList := TStringList.Create ;
try
MainForm.Cursor := crHourGlass;
AList.Assign(MainForm.lbIDList.Items);
MainForm.lbIDList.Items.Clear ;
for i:=0 to AList.Count-1do
begin
if Terminated then
break;
MainForm.ProgressBar.Position := i;
nPos := MainForm.lbIDList.Items.IndexOf(AList);
//
if nPos <0 then
begin
MainForm.lbIDList.Items.Add(AList);
MainForm.lbIDList.ItemIndex := MainForm.lbIDList.Count;
end;
end;

finally
MainForm.Cursor := crDefault;
AList.Free ;
end;
end;

end.
 
肯定会慢,并且很可能会出错.
注意,在线程当中,不要直接访问MainForm的东西,特别是VCL,使用Synchronize访问.
并且,一个概念,线程基本上应该只访问属于他自己的东西,需要和主界面通信,一般采用信号机制和PostMessage等。
你的这个功能需求,可以说多线程不会有什么实质性的帮助,根本没有比要采用多线程.只要在主界面中处理,并在循环中添加Application.ProcessMessage即可
 
这样就等于是在主线程中执行了。
我认为您要把10万条记录分成多组多线程比对,然后将结果再比对,这个用多线程实现应该没错,要把Update部分代码放在一个过程里,然后Synchronize,要重载Create,将分组的记录和状态控件由参数传给线程,而不提倡直接在线程中访问主窗口的控件,当然其实传过来的也只是一个指针,但这样至少不会造成线程单元和主窗口单元之间相互引用的问题。。。。
个人感觉用Application.ProcessMessage的效果实在是太差了。。。。
 
楼上的能帮我做一个多组多线程的例子吗?我没有做过这方面的。
我的EMAIL:lfpsoft@163.com
 
邮件已发
 
感谢楼上的,我已明白了在线程当中,不要直接访问MainForm的东西,但是如果我要将10条记录分成多组线程那应该如何处理呢?比如我需要开5个线程进行处理,那用代码如何实现?
 
10万条邮件地址记录,是一排一行吗?就算不用线程也要不了多少时间吧?想办法排序再循环一遍剃除,是不是会好一些呢???
 
起码是有10万以上,多的话会有60、70万。楼上的有好的方法?
 
有一个偏门,就算是一百万也不算太多吧,全导入数据库中,排序,再一个SQL语句 DISTINCT不就把全部重复的数据过滤掉了吗?然后要导出还是要什么不就随你心愿了吗?
 
楼上的确是一个办法,不过我还是想和知道如何使用多线程
 
sl :TStringList;
........
sl.LoadFromFile('text.txt');
sl.Sort;
 
var
sl :TStringList;
begin
sl := TStringList.Create;
sl.LoadFromFile('text.txt');
sl.Sort;
//
end;
 
to:app2001
我看到该题目的第一反映和你一样,就是把它导入数据库,然后用SQL语句实现!真是**所见略同!!知音呐!! 我的qq: 408837422 有空多联系。
to:楼主
程序的目的是解决问题,只要问题解决了,你用什么办法好就用什么办法不就得了?至于你想学多线程,可以下来再看书吗!
另外,按你的方法,自己处理文本比较,大体是用TStringList吧?告诉你,怎么也快不了!我处理几万条记录就得等会儿了!所以解决该问题最理想的办法还是用数据库SQL来处理。记得要加上索引!
 
问题是解决了,晚上结帐。
我还是想多些了解多线程,哪位大侠指导下?我看过一个软件,好像是亿虎邮件搜索器,它合并和滤掉重复邮件地址的功能是很快的,把几个几万的邮件地址合并成一个,然后滤掉所用的时间大概是6分钟左右,不知道他是如何实现的。
 
你的这个根本就没比要用线程,因为没有什么可以会阻塞的.总么弄都最高CPU占100%,出不来120%.唯一的理由就是防止界面相应迟钝。可是这个完全可以使用Application.Procexxx来实现.
没有太大的实际意义,却大大的增加了复杂度,岂不是自讨苦吃.
你的这个循环的效率大概和冒泡排序相当.因此你可以选用大部分情况下效率更高的&quot;快速排序&quot;QuickSort.我记得DELPHI中有这个函数实现.并且好像TStringList.Sort默认就是快速排序。还有,字符串复制本身也有效率损耗,所以尽量不咬进行字符串复制.还有,lbIDList是什么?逐个的插入效率是比较低的,可能需要不断的复制内存,因此可以采用SetCapxxx(TStringList应该有),如果是ListView/MOMO等,逐个插入的效率更低.
算法优化本身就比较复杂,这个不是那么轻松的话题,几句就可以说清的
 
浅谈多线程与子线程
多线程应该是两个子线程以上的应用,用于多个异步操作的迸发执行。
子线程应该是单个子线程的应用,它用于解决界面响应与阻塞式任务执行的矛盾。
数据(最终结果,不再涉及运算)排序可以用子线程来改善程序界面的响应;但用多线程是不会提高效率的,反而要增加系统开销来协调各线程,简直是画蛇添足。
就好象一个人要吃下两碗饭,你说是一碗接一碗的快,还是东一口,西一口的快?
 
慢的原因好大是在于使用了 MainForm.lbIDList.Items.Add(AList);
虽然可用 Items.begin
Update 方法,但都不尽人意。
 
转贴(网上找到的一篇文章,可能有点用处的):
  优秀的数据库应用应当充分考虑数据库访问的速度问题。通常可以通过优化数据库、优化 查询语句、分页查询等途径收到明显的效果。即使是这样,也不可避免地会在查询时闪现一个带有 SQL符号的沙漏,即鼠标变成了查询等待。最可怜的是用户,他(她)在此时只能无奈地等待。遇到急性子的,干脆在此时尝试 Windows中的其它应用程序,结果致使你的数据库应用显示一大片白色的窗口。真是无奈!
  本文将以简单的例子告诉你如何实现线程查询。还等什么,赶快打开Delphi对照着下面的完整源代码试试吧。
  在查询时能够做别的事情或者取消查询,这只是基本的线程查询,在你阅读了Delphi有关线程帮助之后能立刻实现。这里介绍的是多个线程查询的同步进行。
  在Delphi数据库应用中,都有一个缺省的数据库会话 Session。通常情况下,每个数据库应用中只有这一个会话。无论是查询函数修改数据,在同一时间内只能进行其中的一件事情, 而且进行这一件事情的时候应用程序不能响应键盘、鼠标以及其它的 Windows消息。这就是在 窗口区域会显示一片空白的原因所在。当然,只要将查询或数据操纵构造成线程对象,情况会好一些,至少可以接受窗口消息,也可以随时终止查询或数据操纵,而不会在屏幕上显示出太难看的白色。不过,这只是解决了问题的一部分。假如在进行一个线程查询的时候,用户通过 按钮或菜单又发出了另一个查询的命令,这可如何是好,难道终止正在执行的数据库访问吗? 解决之道就是:多线程同步查询。
  实现多线程同步查询的基本思想是,为每一个查询组件(如TQuery组件)创建一个独占的 数据库会话,然后各自进行数据库访问。需要特别注意的是,因为Delphi中的 VCL组件大多都 不是线程安全的,所以应当在线程查询结束后再将DataSource组件与查询组件关联,从而显示 在DBGrid组件中。
  下面的例子只实现了静态的线程同步查询,即线程对象是固定的,并随窗体的创建和销毁 而创建和销毁。你可以就此进行改进,为每一个数据查询或数据操纵命令创建一个单独的线程对象,从而达到多线程同步查询的目的。
  注意:应用程序中的线程不是越多越好,因为线程将严重吞噬CPU资源,尽管看上去并不明显。谨慎创建和销毁线程将避免你的应用程序导致系统资源崩溃。
  下面的例子给出了同时进行的两个线程查询。第一次按下按钮时,线程开始执行;以后每次按下按钮时,如果线程处于挂起状态则继续执行,否则挂起线程;线程执行完毕之后将连接 DataSource,查询结果将显示在相应的DBGrid中。
   { 这里的多线程同步查询演示程序仅包括一个工程文件和一个单元文件 }
  { 窗体中放置的组件有: }
  { 两个Session组件 }
  { 两个Database组件 }
  { 两个Query组件 }
  { 两个DataSource组件 }
  { 两个DBGrid组件 }
  { 一个Button组件 }
  { 除非特别说明,否则上述各组件的属性都取默认值(见各组件注释) }
  { 对于Database组件,就和一般设置一样,有一个正确的连接即可 }
  { 对于Query 组件,需要在各自的属性 SQL中添加一些查询语句,为了 }
  { 看得更清除,建议不要在两个Query 组件中填写相同的查询语句。 }
  unit Unit1;
  interface
  uses
   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
   Db, DBTables, Grids, DBGrids, StdCtrls;
  type
   TForm1 = class(TForm)
   Session1: TSession;
{ 属性SessionName填写为S1 }
   Database1: TDatabase;
{ 属性SessionName选择为S1 }
   Query1: TQuery;{ 属性Database选择为Database1;属性SessionName选择为S1 }
   DataSource1: TDataSource;
{ 属性DataSet设置为空 }
   DBGrid1: TDBGrid;
{ 属性DataSource选择为DataSource1 }
   Session2: TSession;
{ 属性SessionName填写为S2 }
   Database2: TDatabase;
{ 属性SessionName选择为S2 }
   Query2: TQuery;{ 属性Database选择为Database2;属性SessionName选择为S2 }
   DataSource2: TDataSource;
{ 属性DataSet设置为空 }
   DBGrid2: TDBGrid;
{ 属性DataSource选择为DataSource2 }
   BtnGoPause: TButton;
{ 用于执行和挂起线程 }
   procedure FormCreate(Sender: TObject);
{ 创建窗体时创建线程对象 }
   procedure FormDestroy(Sender: TObject);
{ 销毁窗体时销毁线程对象 }
   procedure BtnGoPauseClick(Sender: TObject);
{ 执行线程和挂起线程 }
   private
   public
   end;

   TThreadQuery = class(TThread) { 声明线程类 }
   private
   FQuery: TQuery;
{ 线程中的查询组件 }
   FDataSource: TDataSource;
{ 与查询组件相关的数据感知组件 }
   procedure ConnectDataSource;{ 连接数据查询组件和数据感知组件的方法 }
   protected
   procedure Execute;
override;{ 执行线程的方法 }
   public
   constructor Create(Query: TQuery;
   DataSource: TDataSource);
virtual;
{ 线程构造器 }
   end;

  var
   Form1: TForm1;
   Q1, { 线程查询对象1 }
   Q2: TThreadQuery;
{ 线程查询对象2 }
  implementation
  {$R *.DFM}
  { TThreadQuery类的实现 }
  { 连接数据查询组件和数据感知组件}
  procedure TThreadQuery.ConnectDataSource;
  begin
   FDataSource.DataSet := FQuery;{ 该方法在查询结束后才调用 }
  end;

  procedure TThreadQuery.Execute;{ 执行线程的方法 }
  begin
   try
   FQuery.Open;
{ 打开查询 }
   Synchronize(ConnectDataSource);{ 线程同步 }
   except
   ShowMessage(‘Query Error‘);
{ 线程异常 }
   end;
  end;

  { 线程查询类的构造器 }
  constructor TThreadQuery.Create(Query: TQuery;
DataSource: TDataSource);
  begin
   FQuery := Query;
   FDataSource := DataSource;
   inherited Create(True);
   FreeOnTerminate := False;
  end;

  { 创建窗体时创建线程查询对象 }
  procedure TForm1.FormCreate(Sender: TObject);
  begin
   Q1 := TThreadQuery.Create(Query1, DataSource1);
   Q2 := TThreadQuery.Create(Query2, DataSource2);
  end;

  { 销毁窗体时销毁线程查询对象 }
  procedure TForm1.FormDestroy(Sender: TObject);
  begin
   Q1.Terminate;
{ 销毁之前终止线程执行 }
   Q1.Destroy;
   Q2.Terminate;
{ 销毁之前终止线程执行 }
   Q2.Destroy;
  end;

  { 开始线程、继续执行线程、挂起线程 }
  procedure TForm1.BtnGoPauseClick(Sender: TObject);
  begin
   if Q1.Suspended then
Q1.Resume else
Q1.Suspend;
   if Q2.Suspended then
Q2.Resume else
Q2.Suspend;
  end;

  end.
 
后退
顶部