線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:2249
推到 Plurk!
推到 Facebook!

使用Thread當處理資料一多時,CPU的使用率就會到100%,怎樣可以修改這樣的情況?

答題得分者是:william
shihchin
一般會員


發表:10
回覆:12
積分:4
註冊:2002-12-18

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-11-14 12:19:42 IP:61.66.xxx.xxx 未訂閱
想請問一下,我目前在Thread裡使用ADO對資料庫做更新的動作時,CLIENT一直送資料來我的CPU使用率就會到100%,想請問我應該怎樣更改才不會這樣,底下是我的程式碼: unit UDPServerMain; interface uses Windows, Messages, Graphics, Controls, Forms, Dialogs, IdWinsock2, stdctrls, SysUtils, Classes, IdBaseComponent, IdAntiFreezeBase, IdAntiFreeze, IdComponent, IdUDPBase, IdUDPClient, IdStack, IdUDPServer, IdSocketHandle, Grids, DBGrids, DB, ADODB, DBTables; type TUDPMainForm = class(TForm) SourceGroupBox: TGroupBox; HostNameLabel: TLabel; HostAddressLabel: TLabel; HostName: TLabel; HostAddress: TLabel; UDPServer: TIdUDPServer; UDPAntiFreeze: TIdAntiFreeze; PortLabel: TLabel; Port: TLabel; BufferSizeLabel: TLabel; BufferSize: TLabel; UDPMemo: TMemo; ADOConnection1: TADOConnection; ADOQuery1: TADOQuery; DataSource1: TDataSource; DBGrid1: TDBGrid; procedure FormCreate(Sender: TObject); procedure UDPServerUDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle); private { Private declarations } public { Public declarations } end; type TServerThead = class(TThread) private DataStringStream: TStringStream; procedure DatabaseProcess; protected procedure Execute; override; public constructor Create(APData: TStream); end; var UDPMainForm: TUDPMainForm; implementation const HOSTNAMELENGTH = 80; {$R *.DFM} procedure TUDPMainForm.FormCreate(Sender: TObject); begin HostName.Caption := UDPServer.LocalName; HostAddress.Caption := GStack.LocalAddress; Port.Caption := IntToStr(UDPServer.DefaultPort); BufferSize.Caption := IntToStr(UDPServer.BufferSize); UDPServer.Active := True; end; procedure TUDPMainForm.UDPServerUDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle); begin TServerThead.Create(AData); end; constructor TServerThead.Create(APData: TStream); begin DataStringStream := TStringStream.Create(''); DataStringStream.CopyFrom(APData, APData.Size); FreeOnTerminate := True; inherited Create(False); end; procedure TServerThead.Execute; begin Synchronize(DatabaseProcess); FreeOnTerminate := True; end; procedure TServerThead.DatabaseProcess; var temp1,temp2:string; ADOConnection:TADOConnection; ADOQuery:TADOQuery; begin temp1:=Copy(DataStringStream.DataString,1,5); temp2:=Copy(DataStringStream.DataString,6,Length(DataStringStream.DataString)-5); UDPMainForm.UDPMemo.Lines.Add('Received "' DataStringStream.DataString ); ADOConnection:= TADOConnection.Create(nil); ADOConnection.ConnectionString:=UDPMainForm.ADOConnection1.ConnectionString; ADOConnection.LoginPrompt:=false; ADOConnection.Connected:=true; ADOQuery:= TADOQuery.Create(nil); ADOQuery.Connection:=ADOConnection; ADOQuery.Prepared:=true; ADOQuery.Close(); ADOQuery.SQL.Clear; ADOQuery.SQL.Add('select * from ab'); ADOQuery.SQL.Add('where b = ' #39 temp2 #39); ADOQuery.Open; if ADOQuery.RecordCount>0 then begin ADOQuery.Close; ADOQuery.SQL.Clear; ADOQuery.SQL.Add('update ab'); ADOQuery.SQL.Add('set a = ' #39 temp1 #39); ADOQuery.SQL.Add('where b = ' #39 temp2 #39); ADOQuery.Open; end else begin ADOQuery.Append; ADOQuery.FieldByName('a').AsString:=temp1; ADOQuery.FieldByName('b').AsString:=temp2; ADOQuery.Post; end; ADOQuery.Close(); ADOQuery.Free; ADOConnection.Connected:=false; ADOConnection.Free; DataStringStream.Free; end; end.
william
版主


發表:66
回覆:2535
積分:3048
註冊:2002-07-11

發送簡訊給我
#2 引用回覆 回覆 發表時間:2003-11-14 12:34:53 IP:147.8.xxx.xxx 未訂閱
I think you have misused thread here. You Synchorize in your thread's execute method and it will actullay use the main thread in running the method DatabaseProcess. Perhaps you should not use synchorize and really use the thread... In this case you should call CoInitialize/CoUnInitialize yourself and create all the ADO component inside the thread.
shihchin
一般會員


發表:10
回覆:12
積分:4
註冊:2002-12-18

發送簡訊給我
#3 引用回覆 回覆 發表時間:2003-11-14 14:29:12 IP:61.66.xxx.xxx 未訂閱
我將程式改為這樣還是一樣的情況,不知我哪裡用錯了? procedure TServerThead.Execute; begin CoInitialize(nil); DatabaseProcess; CoUninitialize; end;
william
版主


發表:66
回覆:2535
積分:3048
註冊:2002-07-11

發送簡訊給我
#4 引用回覆 回覆 發表時間:2003-11-14 14:47:10 IP:147.8.xxx.xxx 未訂閱
This should be normal since your thread is using the otherwise idle cpu time to process. BTW, VCL is not thread safe and your code about accessing the form's controls should be 'synchorized'. Perhaps you could set your thread as a lower priority on givig other process more resource.
shihchin
一般會員


發表:10
回覆:12
積分:4
註冊:2002-12-18

發送簡訊給我
#5 引用回覆 回覆 發表時間:2003-11-14 15:49:34 IP:61.66.xxx.xxx 未訂閱
我將Priority設為最低的tpIdle還是相同的情況.
william
版主


發表:66
回覆:2535
積分:3048
註冊:2002-07-11

發送簡訊給我
#6 引用回覆 回覆 發表時間:2003-11-14 17:14:35 IP:147.8.xxx.xxx 未訂閱
引言: 我將Priority設為最低的tpIdle還是相同的情況. < face="Verdana, Arial, Helvetica"> This is normal since you never sleep in your thread. There is no loop in your thread, so no need to sleep anyway. In Windows, you cannot specify how much cpu time you want to put on the thread, Windows will allocate the resource itself. IMHO, making this thread a lower priority should be good enough to make the system responsive to the user. Perhaps you could try async connect mode of the ADO (personally I never try). BTW, depends on you DB opening/closing connection may be time consuming.
elase
一般會員


發表:4
回覆:23
積分:10
註冊:2003-06-05

發送簡訊給我
#7 引用回覆 回覆 發表時間:2003-11-18 17:35:42 IP:61.219.xxx.xxx 未訂閱
應該是因為動態建立 TADOConnection 的關 你可以在 Form 建立一個固定的 TADOConnection 在 Thread 建立 TADOQuery 時連向那個 TADOConnection    
 
procedure TServerThead.DatabaseProcess;
var
  temp1,temp2:string;
  ADOQuery:TADOQuery;
begin
  temp1:=Copy(DataStringStream.DataString,1,5);
  temp2:=Copy(DataStringStream.DataString,6,Length(DataStringStream.DataString)-5);
UDPMainForm.UDPMemo.Lines.Add('Received "'   DataStringStream.DataString );
  ADOQuery:= TADOQuery.Create(nil);
  ADOQuery.Connection:=UDPMainForm.ADOConnection;
  ADOQuery.Prepared:=true;
  ADOQuery.Close();
  ADOQuery.SQL.Clear;
  ADOQuery.SQL.Add('select * from ab');
  ADOQuery.SQL.Add('where b = ' #39 temp2 #39);
  ADOQuery.Open;
  if ADOQuery.RecordCount>0 then
  begin
    ADOQuery.Close;
    ADOQuery.SQL.Clear;
    ADOQuery.SQL.Add('update ab');
    ADOQuery.SQL.Add('set a = ' #39 temp1 #39);
    ADOQuery.SQL.Add('where b = ' #39  temp2 #39);
    ADOQuery.Open;
  end
  else
  begin
    ADOQuery.Append;
    ADOQuery.FieldByName('a').AsString:=temp1;
    ADOQuery.FieldByName('b').AsString:=temp2;
    ADOQuery.Post;
  end;
  ADOQuery.Close();
  ADOQuery.Free;
  ADOConnection.Connected:=false;
  DataStringStream.Free;
end;    
甚至連 TADOQuery 也可以用共用的 利用 Therad 同步處理來控制 同步的方法:
uses SyncObjs;    procedure TServerThead.DatabaseProcess;
var
  temp1,temp2:string;
  LockXY:TCriticalSection;
begin
  LockXY.Create;
  LockXY.Acquire; 
  UDPMainForm.ADOQuery.Close();
  UDPMainForm.ADOQuery.SQL.Clear;
  UDPMainForm.ADOQuery.SQL.Add('select * from ab');
  UDPMainForm.ADOQuery.SQL.Add('where b = ' #39 temp2 #39);
  UDPMainForm.ADOQuery.Open;
  if ADOQuery.RecordCount>0 then
  begin
    UDPMainForm.ADOQuery.Close;
    UDPMainForm.ADOQuery.SQL.Clear;
    UDPMainForm.ADOQuery.SQL.Add('update ab');
    UDPMainForm.ADOQuery.SQL.Add('set a = ' #39 temp1 #39);
    UDPMainForm.ADOQuery.SQL.Add('where b = ' #39  temp2 #39);
    UDPMainForm.ADOQuery.Open;
  end
  else
  begin
    UDPMainForm.ADOQuery.Append;
    UDPMainForm.ADOQuery.FieldByName('a').AsString:=temp1;
    UDPMainForm.ADOQuery.FieldByName('b').AsString:=temp2;
    UDPMainForm.ADOQuery.Post;
  end;
  LockXY.Release;
  LockXY.Free;
end;    
shihchin
一般會員


發表:10
回覆:12
積分:4
註冊:2002-12-18

發送簡訊給我
#8 引用回覆 回覆 發表時間:2003-11-20 11:20:54 IP:203.70.xxx.xxx 未訂閱
我之前雖然CPU使用率是100%,卻不會妨礙我的程式做其他的動作,例如點選BUTTON,MEMO輸入資料....等,可是我使用了你的方法後,雖然CPU的使用率降低到70%左右,但我在點選BUTTON或MEMO輸入資料,卻反應很慢,感覺比我之前更像是CPU使用率到100%.    
引言: 應該是因為動態建立 TADOConnection 的關 你可以在 Form 建立一個固定的 TADOConnection 在 Thread 建立 TADOQuery 時連向那個 TADOConnection
 
procedure TServerThead.DatabaseProcess;
var
  temp1,temp2:string;
  ADOQuery:TADOQuery;
begin
  temp1:=Copy(DataStringStream.DataString,1,5);
  temp2:=Copy(DataStringStream.DataString,6,Length(DataStringStream.DataString)-5);
UDPMainForm.UDPMemo.Lines.Add('Received "'   DataStringStream.DataString );
  ADOQuery:= TADOQuery.Create(nil);
  ADOQuery.Connection:=UDPMainForm.ADOConnection;
  ADOQuery.Prepared:=true;
  ADOQuery.Close();
  ADOQuery.SQL.Clear;
  ADOQuery.SQL.Add('select * from ab');
  ADOQuery.SQL.Add('where b = ' #39 temp2 #39);
  ADOQuery.Open;
  if ADOQuery.RecordCount>0 then
  begin
    ADOQuery.Close;
    ADOQuery.SQL.Clear;
    ADOQuery.SQL.Add('update ab');
    ADOQuery.SQL.Add('set a = ' #39 temp1 #39);
    ADOQuery.SQL.Add('where b = ' #39  temp2 #39);
    ADOQuery.Open;
  end
  else
  begin
    ADOQuery.Append;
    ADOQuery.FieldByName('a').AsString:=temp1;
    ADOQuery.FieldByName('b').AsString:=temp2;
    ADOQuery.Post;
  end;
  ADOQuery.Close();
  ADOQuery.Free;
  ADOConnection.Connected:=false;
  DataStringStream.Free;
end;    
甚至連 TADOQuery 也可以用共用的 利用 Therad 同步處理來控制 同步的方法:
uses SyncObjs;    procedure TServerThead.DatabaseProcess;
var
  temp1,temp2:string;
  LockXY:TCriticalSection;
begin
  LockXY.Create;
  LockXY.Acquire; 
  UDPMainForm.ADOQuery.Close();
  UDPMainForm.ADOQuery.SQL.Clear;
  UDPMainForm.ADOQuery.SQL.Add('select * from ab');
  UDPMainForm.ADOQuery.SQL.Add('where b = ' #39 temp2 #39);
  UDPMainForm.ADOQuery.Open;
  if ADOQuery.RecordCount>0 then
  begin
    UDPMainForm.ADOQuery.Close;
    UDPMainForm.ADOQuery.SQL.Clear;
    UDPMainForm.ADOQuery.SQL.Add('update ab');
    UDPMainForm.ADOQuery.SQL.Add('set a = ' #39 temp1 #39);
    UDPMainForm.ADOQuery.SQL.Add('where b = ' #39  temp2 #39);
    UDPMainForm.ADOQuery.Open;
  end
  else
  begin
    UDPMainForm.ADOQuery.Append;
    UDPMainForm.ADOQuery.FieldByName('a').AsString:=temp1;
    UDPMainForm.ADOQuery.FieldByName('b').AsString:=temp2;
    UDPMainForm.ADOQuery.Post;
  end;
  LockXY.Release;
  LockXY.Free;
end;    
elase
一般會員


發表:4
回覆:23
積分:10
註冊:2003-06-05

發送簡訊給我
#9 引用回覆 回覆 發表時間:2003-11-20 19:35:31 IP:61.219.xxx.xxx 未訂閱
不清楚你的實際情況為何 看看你要不要用 TIdTCPServer 它有支援Thread 只要使用 TIdThreadMgrDefault 原件    server 程式
 
unit Unit1;    interface    uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdThreadMgr, IdThreadMgrPool, IdBaseComponent, IdComponent,
  IdTCPServer, IdThreadMgrDefault, StdCtrls, DB, ADODB, SyncObjs;    type
  TForm1 = class(TForm)
    IdTCPServer1: TIdTCPServer;
    IdThreadMgrDefault1: TIdThreadMgrDefault;
    ADOConnection1: TADOConnection;
    ADOQuery1: TADOQuery;
    procedure IdTCPServer1Execute(AThread: TIdPeerThread);
  private
    { Private declarations }
  public
    { Public declarations }
  end;    var
  Form1: TForm1;    implementation    {$R *.dfm}    procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
  temp1,temp2:string;
  LockXY:TCriticalSection;
begin
  temp1:=AThread.Connection.ReadLn();
  temp2:=AThread.Connection.ReadLn();      LockXY:=TCriticalSection.Create;
  LockXY.Acquire;      ADOQuery1.Close();
  ADOQuery1.SQL.Clear;
  ADOQuery1.SQL.Add('select * from ab');
  ADOQuery1.SQL.Add('where b = ' #39 temp2 #39);
  ADOQuery1.Open;
  if ADOQuery1.RecordCount>0 then
  begin
    ADOQuery1.Close;
    ADOQuery1.SQL.Clear;
    ADOQuery1.SQL.Add('update ab');
    ADOQuery1.SQL.Add('set a = ' #39 temp1 #39);
    ADOQuery1.SQL.Add('where b = ' #39  temp2 #39);
    ADOQuery1.ExecSQL;
  end
  else
  begin
    ADOQuery1.SQL.Text := 'insert into ab values ('  #39 temp1 #39  ',' #39  temp2  #39  ')';
    ADOQuery1.ExecSQL;
  end;
  LockXY.Release;
  LockXY.Free;
end;    end.
Client 程式
 
unit Unit1;    interface    uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
  StdCtrls;    type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Button1: TButton;
    IdTCPClient1: TIdTCPClient;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;    var
  Form1: TForm1;    implementation    {$R *.dfm}    procedure TForm1.Button1Click(Sender: TObject);
begin
IdTCPClient1.Connect();
IdTCPClient1.WriteLn(edit1.Text);
IdTCPClient1.WriteLn(edit2.Text);
IdTCPClient1.Disconnect;
end;    end.
william
版主


發表:66
回覆:2535
積分:3048
註冊:2002-07-11

發送簡訊給我
#10 引用回覆 回覆 發表時間:2003-11-21 09:10:04 IP:147.8.xxx.xxx 未訂閱
Hi elase, may I ask you why you choose to use a local variable as the critical section here  > class="code">{ global/shared variable } gCS: TCriticalSection; { threads } Thread1,Thread2: TMyThread; { ... } procedure TMyThread.Execute; begin { ... } gCS.Enter; try { ... } finally gCS.Leave; end; { ... } end;
shihchin
一般會員


發表:10
回覆:12
積分:4
註冊:2002-12-18

發送簡訊給我
#11 引用回覆 回覆 發表時間:2003-11-21 10:12:39 IP:203.70.xxx.xxx 未訂閱
我是要用UDP的方式去傳送訊息,所以才選擇使用TIdUDPServer.    
引言: 不清楚你的實際情況為何 看看你要不要用 TIdTCPServer 它有支援Thread 只要使用 TIdThreadMgrDefault 原件
allanchou
一般會員


發表:9
回覆:35
積分:8
註冊:2003-04-01

發送簡訊給我
#12 引用回覆 回覆 發表時間:2003-11-21 12:15:00 IP:61.30.xxx.xxx 未訂閱
其實只要SleepEx 一下應該就可以了
elase
一般會員


發表:4
回覆:23
積分:10
註冊:2003-06-05

發送簡訊給我
#13 引用回覆 回覆 發表時間:2003-11-21 13:46:19 IP:61.219.xxx.xxx 未訂閱
是我錯了,我沒注意。
系統時間:2024-05-10 14:42:34
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!