同一秒钟启动40个线程(有源码)(200分)

  • 主题发起人 junrui2726
  • 开始时间
J

junrui2726

Unregistered / Unconfirmed
GUEST, unregistred user!
我写了一个线程(MyTread),这个线程从一张表里一次取出一条数据,用memo显示出来后进行处理,然后就把该条数据删除,后把删除的数据插入到一个备份表里。要求是每一秒钟处理100条,也就是在21秒处理100条,22秒有处理100条。怎么在一秒钟内同时启动100个MyTread线程呢?是在同一秒?? 下面是我简单写的线程,没实用性,只是拿来说明而已。
MyTread = class(TThread)
private
FADOConnection :TADOConnection;
FADOQuery :TADOQuery;
FDataSource :TDataSource;
protected
procedure Execute;
override;
end;

implementation

procedure MyTread.Execute;
var
i :integer;
DispMemo :string;
insertStr :string;
begin
freeonterminate:=true;
while not Terminateddo
begin
CoInitialize(0);
FADOConnection := TADOConnection.Create(nil);
FADOQuery := TADOQuery.Create(nil);
FDataSource := TDataSource.Create(nil);
try
FADOConnection.Close;
FADOConnection.ConnectionString := 'Provider=SQLOLEDB.1;Password=22;Persist Security Info=True;User ID=sa;Initial Catalog=sas;Data Source=HJ';
FADOConnection.Open;
FADOQuery.Connection := FADOConnection;
FDataSource.DataSet :=FADOQuery;
form1.Edit1.Text :=timetostr(time);
EnterCriticalSection(CriticalMy);//进入临界段
FADOQuery.Close;
FADOQuery.SQL.Clear;
FADOQuery.SQL.Add('select top 1 id,nnr,csr,gzr,bjr,tjr,');
FADOQuery.sql.Add('hnr,hbr,slr,dlr,xhr,fre,fgf,tuiff,');
FADOQuery.sql.Add(' from hj1 order by Priority desc');
FADOQuery.Open;
if FADOQuery.RecordCount =0 then
exit;

DispMemo:=' [ '+timetostr(time)+' ] '
+midstr(FADOQuery.FieldByName('nnr').AsString,3,length(FADOQuery.FieldByName('nnr').AsString))+' '
+FADOQuery.FieldByName('bjr').AsString+' '
+format('%x',[FADOQuery.FieldByName('hnr').asinteger])+' '
+FADOQuery.FieldByName('slr').AsString+' '
+FADOQuery.FieldByName('tuiff').AsString;
form1.Memo1.Lines.Add(DispMemo);
fadoquery.Delete;
try
insertStr:='insert into hj2 (fgf,ert,fdfd,dff,iuy,yuu,yuyy,MessageContent)'+
'values ('''+ FADOQuery.FieldByName('nnr').AsString+''','''+midstr(FADOQuery.FieldByName('nnr').AsString,3,length(FADOQuery.FieldByName('nnr').AsString))+''','+
''''+FADOQuery.FieldByName('hnr').Asstring+''','''+FADOQuery.FieldByName('bjr').Asstring+''','+
''''+FADOQuery.FieldByName('tuiff').AsString+''''+')';

FADOQuery.Close;
FADOQuery.SQL.Clear;
FADOQuery.SQL.Add(insertstr);
FADOQuery.ExecSQL;
except
form1.Memo1.Lines.Add('增加备份表出错了!');
end;
LeaveCriticalSection(CriticalMy);//退出临界段
finally
CoUninitialize;
FreeAndNil(FADOConnection);
FreeAndNil(FADOQuery);
FreeAndNil(FDataSource);
end;
sleep(1000);
end;

end;

如果用
for k:=1 to 100do
begin
mytread1:=mytread.Create(false);
end;
根本起不到我要的效果。请各位指点指点。怎么在一秒钟内同时启动100个MyTread线程呢?是在同一秒??或者在同一秒钟处理100条数据?只要能实现这种功能就行。
 
不用线程还快
 
有100个cpu还有可能。呵呵。
 
to ivw 你说的这种方法怎么实现呢?
请各位给点建议呀
 
你这样的话等于是以下有100个连接连上数据库,速度肯定变慢的。应该就放一个线程,然后再这个线程里循环执行。
 
线程实际上是一个很慢的东西,只是给人感觉在后台执行,直接写在程序中反而更快!!
 
那能不能在一秒内并发做这么多工作呢
 
各位大哥帮忙呀,主要能实现我要的功能就行,方法不限呀
 
看起来很蒙!
 
作show还可以,不过不现实,
也值得顶一下!!
 
楼主可以换一个角度来处理,完全可以使用存储过程来处理,复杂的处理全部交给sql server去处理,客户端只负责显示memo就可以了。
细节楼主可以自己完善,如事务保护等等,简单描述为:

create procedure test
as
begin
select top 100 a.id,a.memo1
into #temp1
from table1 a
insert into table2 (memo1) values
from (select a.memo1
from table1 a
where a.id in (select b.id from #temp1 b))
delete from table1 a
where a.id in (select b.id from #temp1 b)
select *
from #temp1
drop table #temp1
end
 
来自:junrui2726, 时间:2004-5-7 17:45:34, ID:2597260
那能不能在一秒内并发做这么多工作呢
概念性错误,100%不可能的,线程对同一个对象操作必须要互斥,必须要。
即使是两个线程对一个字节的内存变量操作也要互斥。何况是数据库。。
还有,他们说的是对的,多线程未必越多越快,因为,只有一两个cpu,
而操作系统是把cpu时间分割给每个线程,也就是切换,切换本身也要cpu时间的,
所以当线程太多的时候 反应就会变慢 开一两个还差不多,一般也不要超过6个。。。
 
最近研究了线程使用数据库的问题,提提我的看法:
①、你的要求是“每一秒钟处理100条”,是不是每条记录的处理就要用到一秒中呢?如果每条记录的处理只需要半秒钟时间,只要50个线程就可以了。100个线程似乎太多!没必要。线程切换场景要时间的。
②、完全可以使用存储过程来处理,这样好一些。
③、DataSource这里好像没必要存在?在每个循环中创建下列:
FADOConnection := TADOConnection.Create(nil);
FADOQuery := TADOQuery.Create(nil);
FDataSource := TDataSource.Create(nil);
没必要吧,在循环之前创建就可以了,不需要销毁。这要花时间的。
④、最重要的一点:我认为这里不需要进入临界区!sleep(1000);也没必要!
如果进入临界区,除了在后台进行之外,100个操作其实是按顺序执行的,没有并发执行。
⑤、使用Memo,需要syschronize,为了能正常显示结果,可能要刷新一下。或ProcessMessage.

 
to :刘麻子
你说得对,线程对同一个对象操作必须要互斥,即使我开多个同样线程,那些线程如果同时对一条数据进行删除就会抱错,所以只能设置临界区,只有一个线程处理完了再到另外一个线程,得到的结果就跟开一个线程一样了。
to :crazymoon
①、你可能理解错了,我要的是每次取出一条(而不是100条)数据处理,处理完后删除这条数据,再把删除的数据插入到另一张表中,比如table1有100000条数据,首先取出第一条数据处理后进行删除,后插入到table2,完后再取出第二条数据处理后进行删除,后插入到table2,完后再取出第三条数据处理后进行删除,后插入到table2,但必须在1秒钟内完成100数据的处理(其中每条记录的处理就要用到差不多一秒中)。
②、你说的第③、点是对的,我疏忽了,谢谢
③、不设临界区该怎么做呢?多个线程不可能同时对同一条数据进行删除吧。比如我取出第一条记录正在处理,但还没有删除,你又取得出第一条记录处理,也还没有删除,依次类推,不是取出第一条记录处理N遍了,这样数据就不一致了,还有如果你同时删除该记录会怎样呢?
我要的就是这样的,id是唯一的。
//首先取出一条记录
select top 1 @id=id ,....from table1 order by time desc
....................
............//对数据进行处理
delete from table1 where id=@id
insert into table2 (........) values (......)//把取出来的记录插入
这样代码处理后再反复循环处理,处理的记录就不会一样了

 
①、在这里Sleep(1000)问题较大,整个程序暂停一秒,怎么也快不起来!
②、临界区最好不要进入,100个线程的临界区如果是同一个,实际就是按顺序执行的。
{鼠标坏了,不方便看你的原文了}
你的算法有问题,对数据表而言,同一时刻只处理了一条记录。用多线程的方法应该是
同一瞬间对100条记录同时进行删除,当然这100条记录不能是重复的。但可以同时对1~100条记录进行删除呀。(??不知道有没问题,没试过)
要想多个线程不对同一条数据进行操作删除还是有可能的。说明一下,没试过。
首先得到表的记录总数。Reccount将其分成几个部分。比如线程一处理1~50条记录。
线程二处理第51~100记录。这样也可以啊。
 
好象没必要用多线程
 
to :crazymoon ,谢谢你的发言。
你说的好象有道理,但“同一时刻只处理了一条记录。用多线程的方法应该是同一瞬间对100条记录同时进行删除,当然这100条记录不能是重复的。但可以同时对1~100条记录进行删除呀”这个怎么处理呢,代码应该怎么写呢?
“要想多个线程不对同一条数据进行操作删除还是有可能的。说明一下,没试过。
首先得到表的记录总数。Reccount将其分成几个部分。比如线程一处理1~50条记录。
线程二处理第51~100记录”这个怎么处理呢,代码应该怎么写呢?
能否给个具体的实例或者一些代码呢
希望大家继续提出建议
 
To junrui2726:
在这种问题中别想用线程的方法提高性能,因为你只有一个Cpu,线程不能提高速度,
过多的线程反而降低性能。
 
xeen:
一个任务分解到多个CPU去执行,当然是最好的。
但一个任务分解到一个CPU的多个时间片去处理,也并非完全不可以。虽然对CPU而言,
实际还是应该类似顺序的一种执行方式。但至少感觉上是能提高速度的。
to junrui2726:
我写的代码,你试试看。//我没试过,如果数据库支持并发操作,应该可以!
// 一个主连接,主查询
var sRecCount,n,m,l,k:integer;
Main.Query.Sql.Text:='select * from TestTable';
Main.Query.Open;
sRecCount:=Main.Query.RecCount;
m:=(sRecCount div 100)+1;//100的倍数
For l:=0 to m-1do
begin

For n:=0 to 100do
begin

//第一次创建100个线程处理1~100条记录
//第二次创建100个线程处理101~200条记录
//线程运行完毕后自动销毁
k:=l*100+n;
MyThread.Create(false,k)
end;
sleep(100);
end;
////////////////////////////////////////////////
MyThread=Thread
private
RecNo:string;
publice
procedure TrdProc;
end;
//////
Thread.Create(false,RecNo)
begin
Cn:=AdoConnection.Create(nil);
//在这里还是每次运行线程都创建了连接,因为ADO会缓存连接,估计问题不大。
Cn.ConnectionString:='-----';//
Q:=AdoQuery.Create(nil);
Q.Connection:=Cn;
FreeeOntermenated:=true;
RecNo:=RecNo;
end;
Thread.Excute
begin
activex.coinitialnize;
TrdProc;
activex.CoUninitialnize;
end;
Thread.TrdProc
begin
Q.Sql.text:='select * from TestTable where Id='+inttostr(RecNo);
Q.open;
Syschronize(form1.memo1.lines.Add(Q.FieldValues['TestField']));
Q.Sql.text:=Insert into Table2 ---';///
Q.exeSql;
end;

end;



 
mark 以下。学习。
 
顶部