I think that if you need to receive results after querying data, then you should use an IFuture instead of a conventional Thread only.
So, you could launch an anonymous thread or any other, preferably I think a "TASK" would be more suitable for parallel processing, and, from within this thread you would call IFUTURE tasks to process the query data.
In the end, you would have the expected results, however, in a more appropriate way and using the parallel processing power of your system
-- objects: TTask and IFuture
see my sample: https://bbs.2ccc.com/topic.asp?topicid=680095
.
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
CDS1.Close; CDS1.CommandText:='select sum(Panels) as 生产板数,'+
'sum(case when (DownTime > '''+ FDTime+''') and (PlanType=''计划外停机'' or PlanType is null) then DownTime else 0 end) as 计划外停机, '+
'SUM(ATime) AS 计划开机时间,'+
'(1-sum(case when DownTime > '''+ FDTime+''' then DownTime else 0 end)/SUM(ATime)) * 100 as 时间稼动率,'+
'SUM(Points) AS 实际点数,'+
'sum(IPC*(1-(case when DownTime > '''+ FDTime+''' then DownTime else 0 end)/ATime)) AS 理论点数,'+
'SUM(Points)/sum(IPC*(1-(case when DownTime > 0 then DownTime else 0 end)/ATime)) *100 as 性能稼动率, '+
'(1-(sum(case when (DownTime > '''+ FDTime+''') and (PlanType=''计划外停机'' or PlanType is null) then DownTime else 0 end))/'+ '(SUM(ATime)-sum(case when PlanType=''计划内停机'' then DownTime else 0 end)) ) * '+ '(SUM(Points)/sum(IPC*(1-(case when DownTime > 0 then DownTime else 0 end)/ATime))) * 100 as 设备OEE,'+ 'SUM(Points) / (DATEDIFF(minute, '''+SDate+''', getdate())/60.0) as 小时产能,'+ 'SUM(Points)/sum(Panels) as 单板点数,count(DISTINCT ProName) as 生产面数,'+ 'sum(case when (DownTime > '''+ FDTime+''') and (PlanType=''计划内停机'') then DownTime else 0 end) as 计划内停机,'+ 'SUM(Points) / (DATEDIFF(minute, '''+SDate+''', getdate())/60.0) * (DATEDIFF(minute, '''+SDate+''', '''+EDate+''')/60.0) as 产能预估 from '+
'(select VITestData.ADate,VITestData.ALine,case when VITestData.AShift=0 then ''白班'' else ''晚班'' end as AShift,VITestData.ProName,'+ 'VITestData.ATime,SmtCycle.ACycle,VITestData.ATime - SmtCycle.ACycle as DownTime,ModuleList.Points * ModuleList.Panels as Points,'+ 'ALineList.IPC / 60 * ATime as IPC,'+ 'ModuleList.Panels,VITestData.CauType,DownType.PlanType from VITestData '+
'left join (select ModuleID,Side,Panels,Points from ModuleList) as ModuleList '+ 'on ModuleList.ModuleID = VITestData.ModID and ModuleList.Side = VITestData.Side '+ 'left join SmtCycle on VITestData.ModID = SmtCycle.ModID and VITestData.Side = SmtCycle.Side and VITestData.ALine = SmtCycle.ALine '+ 'left join ALineList on VITestData.ALine = ALineList.ALine '+ 'left join DownType on DownType.DownType = VITestData.CauType '+ 'where (VITestData.ADate between '''+SDate+''' and '''+EDate+''') and (VITestData.ATime > 0)) as OEEData '; CDS1.Open;
if CDS1.FieldByName('设备OEE').AsFloat < GetStandValues('SMT设备OEE') then begin Circle1.Stroke.Color:=TAlphaColors.Tomato; end else begin Circle1.Stroke.Color:=TAlphaColors.Springgreen; end;
----------------------------------------------
【个人签名】:玩了多年DELPHI,终于从菜鸟升级成老菜鸟
1) as a DB query can be time-consuming, you could create a thread (TASK / IFUTURE) for it. As what matters in this case is the result of the query, then a "task-IFUTURE" would be appropriate, as the rest of the initial procedure necessarily depends on the result of the query. So we're talking about "future thing", and that's where "IFUTURE" comes into play!
2) you can use as many TASK/IFUTURE as you need, however, you should always think that it may be necessary to cancel the task, so always provide a way to control the end of the task, if you wish. And also, always think that something can go wrong, so also think about handling an "exception", using the "TRY-EXCEPT" concept.
3) as a thread/task/ifuture can be running when the user closes the application, or form, so also think about controlling this, observing if there is any thread/task running, etc...
4) how task updates will be shown to the user, then also think about synchronizing thread/task with thread-main using the "synchronize/queue" procedures. As updates can be many, so also think about updating from time to time, that is, for example, every 10% update the screen, etc...
5) working with thread/task is not trivial, so it takes a lot of testing to find the most appropriate way, as there are several ways to do the same task. There is no magic recipe, however, there are more appropriate ways for each scenario.
6) always try to create small procedures, this way, you will have an easier way to find problems. If a process contains many lines of code, try dividing it into smaller portions. However, do not create too many, as this also makes it difficult to find errors. Maybe 10 lines of code would be ok, however, each case is different.
7) try to eliminate excessive texts within the code, for example, SQL expressions... this only hinders the search for errors. Try to create a unit just for the texts, for example, put your SQL expressions (text) in a unit specific to them, so, in your code to be executed, you can use the variables or constants that represent the text (SQL or no), example:
const // if you don't need to change the text MySQLText : string = 'xxxx xxxx xxxx'; var MySQLText : string = 'zzzz zzzz zzzz'; // if you need to use the variable for other text - not recommended
however, you can still change the value using parameters in Delphi, for example the "FORMAT()" function and "%s", "%d", etc... whether in constants or variables
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
procedure TForm1.MyListStr; var i,x:Integer; begin for i := 1 to 10000 do begin x:=Random(10000); Memo1.Lines.Add(IntToStr(x)); ListBox1.Items.Add(IntToStr(x)); end; Button1.Text:=IntToStr(ListBox1.Items.Count)+'-'+IntToStr(Memo1.Lines.Count); end;
procedure TForm1.Button1Click(Sender: TObject); begin TThread.CreateAnonymousThread(MyListStr).Start; end;
3 visual elements been accessed into thread context.... needs be Synchronized or Queued then main-thread can decide when update visual happens
NOTE: thumb-rule, in a thread not access any visual element! if need, then it should be synchronized/queued
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
procedure TForm1.MyListStr; begin SW:=TStopwatch.StartNew; SW.Start; MyList:=TStringList.Create; TTask.Run( procedure var i,x:Integer; begin for i := 1 to 10000 do begin x:=Random(10000); MyList.Add(IntToStr(x)); end;
TThread.Synchronize(nil, procedure begin Memo1.Lines:=MyList; Button1.Text:=IntToStr(Memo1.Lines.Count); Label1.Text:=SW.Elapsed.TotalMinutes.ToString; end); end);
MyList.Free; SW.Stop; end;
procedure TForm1.Button1Click(Sender: TObject); begin ListBox1.Clear; Memo1.Text:=''; MyListStr; end;
procedure TForm1.Button1Click(Sender: TObject); begin ListBox1.Clear; Memo1.Text:=''; MyListStr; end;
改成:
procedure TForm1.Button1Click(Sender: TObject); begin ListBox1.Clear; Memo1.Text:=''; TTask.Run( begin MyListStr; end ); end;
----------------------------------------------
-