如何使用多个线程同时读取文本文件?我给300分!(300分)

  • 主题发起人 主题发起人 pogoo
  • 开始时间 开始时间
P

pogoo

Unregistered / Unconfirmed
GUEST, unregistred user!
本人欲开10个线程,同时读取文本文件data.txt,此文件内容如下:
0.34812
0.98234
0.61222
0.02352
.
.
.
0.88251
数据量很大!
现在,我想用这10个线程同时读取此文件,然后分别存为另外10个文本文件,如:data01.txt,
data02.txt,data03.txt......data10.txt。我应该如何以最有效率的方式完成呢?
谢谢各位!
 
多线程是反复操作,如果文件读取本身是尽人意,不要越搞越糟
 
太遗憾了!是没有人会呢?还是不值得回答?给个说法么!
 
有个建议:
读取文件用STRINGLIST读,
然后,呢用10个线程读STRINGLIST
 
至于代码应该不要了吧,这很简单的呀,等等,给你一个!
 
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
stringlist:tstringlist;
{ Public declarations }
end;

var
Form1: TForm1;
implementation
uses unit2;
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var avg:integer;
begin
stringlist:=tstringlist.Create ;
stringlist.loadfromfile('d:/a.txt');
avg:=stringlist.count div 10;
readtext.create(0,avg-1,'d:/1.txt');
readtext.create(avg,2*avg-1,'d:/2.txt');
readtext.create(2*avg,3*avg-1,'d:/3.txt');
readtext.create(3*avg,4*avg-1,'d:/4.txt');
readtext.create(4*avg,5*avg-1,'d:/5.txt');
readtext.create(5*avg,6*avg-1,'d:/6.txt');
readtext.create(6*avg,7*avg-1,'d:/7.txt');
readtext.create(7*avg,8*avg-1,'d:/8.txt');
readtext.create(8*avg,9*avg-1,'d:/9.txt');
readtext.create(9*avg,stringlist.count,'d:/10.txt');
stringlist.free;
end;

end.

unit Unit2;
interface
uses
Classes,unit1;
type
readtext = class(TThread)
private
begin
pos,endpos:integer;
filename:string;
{ Private declarations }
protected
procedure Execute;
override;
published
constructor create(i,j:integer;savename:string);
end;

implementation
{ Important: Methods and properties of objects in VCL can only be used in a
method called using Synchronize, for example,
Synchronize(UpdateCaption);
and UpdateCaption could look like,
procedure readtext.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end;
}
{ readtext }
procedure readtext.Execute;
var list:tstringlist;
i:integer;
begin
list:=tstringlist.create;
for i:=begin
pos to endposdo
begin
list.add(form1.stringlist);
end;
list.savetofile(filename);
list.free;
end;

constructor readtext.create(i,j:integer;savename:string);
begin
inherited create(true);
FreeOnTerminate := true;
begin
pos:=i;
endpos:=j;
filename:=savename;
end;

end.
没测试过,自己看看
 
但是 TStringList 好象是线程不安全的!?[?]
 
各位老大:
TStringList 是不是线程不安全的!?,能在多线程中用吗?
 
TStringList比较特殊, 对于读操作来说它是Thread-safe的,但对写操作则不是。
 
直接定义一个总txtfile变量
然后在线程里面readln()
 
用txtfile不大好吧,用tfilestream去读吧,将文件分成10等分
每个线程seek一个并且读出其中一块再拼起来
 
多线程读一个文件好像没什么必要,因为要安全读取,得用互斥或临界保护起来,这样线程就
变成阻塞的,其实效率没提高多少,建议用一个线程就可以了,读取期间主线程照常工作
 
用文件映射做,或者用重叠I/O做(推荐),而且文件读写速度和硬盘有关系,你开多个线程好像没有必要,
一个线程就够了
 
Delphi开发人员指南上有这个范例好像。去下载这本书的代码光盘啊。
 
由于不能同时(并发)地操作一个文件,10个线程与一个线程的效果相差不大,况且由于
系统时间片的分配问题,在效率上可能还要差一点,建议读文件时使用一个线程,分析
数据时可以考虑采用多线程
 
天真兄的想法是好的, 现对他的代码整理如下 , 供初学者们参考:
/////////////////////////////////////////////////////////////////
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
StringList: TStringList;
{ Public declarations }
end;

var
Form1: TForm1;
implementation
uses unit2;
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var avg:integer;
begin
StringList:= TStringList.Create ;
stringlist.loadfromfile('d:/a.txt');
avg:=stringlist.count div 10;
readtext.create(0,avg-1,'d:/1.txt');
readtext.create(avg,2*avg-1,'d:/2.txt');
readtext.create(2*avg,3*avg-1,'d:/3.txt');
readtext.create(3*avg,4*avg-1,'d:/4.txt');
readtext.create(4*avg,5*avg-1,'d:/5.txt');
readtext.create(5*avg,6*avg-1,'d:/6.txt');
readtext.create(6*avg,7*avg-1,'d:/7.txt');
readtext.create(7*avg,8*avg-1,'d:/8.txt');
readtext.create(8*avg,9*avg-1,'d:/9.txt');
readtext.create(9*avg,stringlist.count -1,'d:/10.txt');
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
StringList.Free();
end;

end.

/////////////////////////////////////////////////////
unit Unit2;
interface
uses
Classes,unit1;
type
readtext = class(TThread)
private
begin
Pos,
EndPos: Integer;
FileName: string;
protected
procedure Execute;
override;
published
constructor create(i,j:integer;savename:string);
end;

implementation
procedure readtext.Execute;
var List: TStringList;
i: Integer;
begin
List := TStringList.Create;
for i:= begin
Pos to EndPosdo
begin
List.add(form1.stringlist);
end;
List.SaveToFile( FileName );
List.Free;
end;

constructor readtext.create(i,j: Integer;
SaveName: string);
begin
inherited create(false);
FreeOnTerminate := true;
begin
Pos := i;
EndPos := j;
FileName := SaveName;
end;

end.
 
To: popo 先分割文件,然后用多线程(每个线程读一个文件)。再合并文件
 
天真的想法是好的,不过我觉得不好用,因为数据量很大,会占掉很多内存(甚至系统当机)。
我觉得用一个线程就好,因为读数据的瓶颈在磁盘而不在CPU,用多线程效率提高不大,甚至更
慢。这一点在平时拷贝文件时可以体现,同时开多个资源管理器拷贝文件,效率并没提高。
可以直接用文件读写,开一个大缓冲区,一次读写十几兆(十几兆内存应该不成问题吧)。
 
接受答案了.
 
后退
顶部