使用TTimer和使用TThread有什么区别

时间:2015-09-15 08:06:42

标签: multithreading delphi

我开发了一个连接到SQL Server数据库的应用程序,每隔1秒从表中读取一些数据 为此,我使用TTimer,但数据库响应的延迟会影响我的应用程序性能。

我对Delphi中的TThread了解一点,我现在想知道的是使用TTimerTThread之间的区别?在这种情况下,使用TThread代替TTimer对我的应用程序性能有用吗?

5 个答案:

答案 0 :(得分:3)

TTimer是一个基于消息的计时器。它将WM_TIMER消息发布到创建它的线程的消息队列中。您的数据库操作阻止该线程及时处理新消息。假设您的TTimer位于主UI线程中,这就是您的应用程序性能受损的原因。将数据库操作移动到工作线程可防止主线程的消息循环被阻止。

答案 1 :(得分:3)

两者之间的主要区别可以在他们的班级定义中找到:

  • TTimer = class(TComponent)

  • TThread = class

虽然TTimer类扩展TComponent并且是组件本身,但TThread是一个扩展TObject的抽象类。

TThread公开了TThread.Sleep之类的静态方法和一种名为Execute的特殊保护方法,它必须在派生类中实现才能执行所需的工作。 TThread直接使用来宾操作系统的Processes and Threads功能。

  

...为此我使用TTimer但数据库响应的延迟会影响我的应用程序性能

发生这种情况的原因是因为OnTimer对象的TTimer事件在调用线程中执行:将TTimer组件放入表单并将其{{1实现了event,代码在主线程中执行。

OnTimer方法更灵活:如果由于某种原因必须在主线程中执行代码,则可以实现在线程内TThread嵌套Execute TThread方法。

如果您想在一段时间间隔后以重复方式执行数据库请求,最好考虑将TEventTEvent对象结合使用。

使用TMyThread = class(TThread) private FInterval: Integer; FWaitEvent: TEvent; protected procedure Execute; override; procedure TerminatedSet; override; public constructor Create(Interval: Cardinal; CreateSuspended: Boolean); destructor Destroy; override; end; 的类定义示例:

constructor TMyThread.Create(Interval: Cardinal; CreateSuspended: Boolean);
begin
  inherited Create(CreateSuspended);
  FInterval := Interval;
  FWaitEvent := TEvent.Create(nil, False, False, '');
end;

destructor TMyThread.Destroy;
begin
  FWaitEvent.Free;
  inherited;
end;

procedure TMyThread.TerminatedSet;
begin
  inherited;
  FWaitEvent.SetEvent;
end;

procedure TMyThread.Execute;
begin
  inherited;
  while not Terminated do begin
    //do your stuff

    //wait fo some amount of time before continue the execution
    if wrSignaled = FWaitEvent.WaitFor(FInterval) then
      Break;
  end;
end;

已实施的课程:

WaitFor

FWaitEvent对象上调用的TerminatedSet方法允许等待所需的时间。

线程的FWaitEvent方法的实现允许将class User has_one :authenticity end class Authenticity belongs_to :user end u = User.first u.authenticate = Authenticate.create 对象置于信号状态,然后在间隔过去之前退出线程

答案 2 :(得分:3)

这并没有专门针对你的q,但正如对其中一个的评论所述 其他答案,以您正在进行的频率轮询数据库并不是一个好主意,特别是如果其他用户试图访问它。

有多种方法可以在数据更改时从数据库服务器获取通知,而无需不断地轮询它们。这篇Embarcadero论文对各种DBMS的可用内容进行了非常有用的回顾:

http://docwiki.embarcadero.com/RADStudio/XE8/en/Database_Alerts_%28FireDAC%29

如果您的Delphi版本包含FireDAC,您可以从链接中看到,如果您的DBMS支持,您可以使用TFDEventAlerter接收服务器上的数据更改通知 它

如果您使用的是Interbase或Firebird(可能还有其他一些),则可以使用其他Delphi组件,这些组件不需要FireDAC,例如:适用于Interbase的IBExpress ibrary中的TIBEventAlerter。

答案 3 :(得分:2)

如果您想要在主表单上

,我建议保留您的TTimer

然后在你的TTimer中创建一个TTask

http://docwiki.embarcadero.com/RADStudio/XE8/en/Tutorial:_Using_Tasks_from_the_Parallel_Programming_Library

https://delphiaball.co.uk/2014/09/08/using-ttask-from-the-parallel-programming-library/

并且在那里完成所有数据库工作,但正如其他人建议每1秒检查一次并不是很好的做法。

这样的事情:

<tr ng-repeat="item in directiveinfo"> <td> {{item.name}} </td> <td ng-repeat="(key,value) in item"> <input type=checkbox ng-model="value"> </td> </tr>

Global var downloaddata : ITask

有更好的解决方案,这只是一个快速的基本答案,但它应该指导你做更好的事情。

在您的线程中执行逻辑将保持您的UI代表性,但要注意TThread.Syncronize将等待主窗体并根据情况TThread.queue将是一个更好的调用。

答案 4 :(得分:0)

无论使用TTimer还是TThread,建议仅运行查询以获取已更改的数据。为此,您需要:

  • 向每个表添加“已修改”(TIMESTAMP)列
  • 向每个表添加“已删除”(TIMESTAMP)列
  • 添加用于INSERT或UPDATE的触发器,以使用CURRENT_TIMESTAMP更新“已修改”字段
  • 在“修改”字段上添加DESC索引以加快查询速度
  • 从不删除行,仅使用CURRENT_TIMESTAMP更新“已删除”字段

第一次阅读后,索要新数据就足够了:

select c.* from 'customers' as c where c.modified > '2019...'

您一次读取所有数据,并将结果存储在临时内存阵列中。
关闭数据集>>后,将您与主数组进行比较(同步)。

要更新数据>>运行单独的SQL。