我有一些需要定期执行的数据库优化例程。我目前正在使用TTimer,但主要的VCL冻结并且非常hacky ...我想知道什么是最好的方法是具有低CPU消耗并执行这些例程。我认为将例程放在具有低线程优先级的单独线程中是最好的方法。
有什么想法吗?
答案 0 :(得分:3)
如果可能的话,最好只编写所有线程来完成在特定时间完成的最重要的事情。如果您不确切知道自己在做什么,那么弄乱线程优先级会导致serious performance problems。相反,只需像这样编写你的线程:
有什么重要事吗?如果是这样的话。
有什么不重要的事吗?如果是这样,请做一点。
转到第1步。
假设你使用线程优先级。想象一下:
低优先级任务A抓取数据库锁。
普通优先级任务B需要大量CPU时间,它会从低优先级任务中窃取CPU。
普通优先级任务C需要访问数据库。但它无法运行,因为低优先级任务保持对数据库的锁定,任务B使CPU通过任务A。
现在,任务C必须等到任务B完成才能访问数据库。但它应该是任务B的时间限制。
答案 1 :(得分:1)
这样做的一种方法是创建“db optimization thread”,例如:
type
// a record defining database connection
TConnectionSettings = record
DatabaseName: string;
Server: string;
Port: Word;
UserName: string;
Password: string;
end;
type
TDBOptimizationThread = class(TThread)
private
FConnection: TDatabaseConnection; // your database connection... I don't know what libraries you are using
FQuery: TQuery; // your specific db query
protected
procedure Execute; override;
public
constructor Create(AConnectionSettings: TConnectionSettings;
destructor Destroy; override;
end;
implementation
constructor TDBOptimizationThread.Create(AConnectionSettings: TConnectionSettings;
begin
inherited Create(True); // create suspended
//FreeOnTerminate := True; // if you want it to be freed when you terminate it
// create FConnection and FQuery objects
// setup FConnection parameters based on AConnectionSettings
end;
destructor TDBOptimizationThread.Destroy;
begin
// destroy objects
inherited Destroy;
end;
procedure TDBOptimizationThread.Execute;
begin
while NOT Terminated do
try
// check if it's time to run query
// you can use a private variable of TDateTime type that will hold
// last timestamp of when the query ran, etc.
if ItsTimeToRunQuery then begin
// check if we still have db connectivity
if NOT FConnection.Connected then
// ouch, try to connect...
FConnection.Connect;
FQuery.SQL.Text := 'Your optimization query';
FQuery.Execute; // or ExecSQL or whatever the method is based on your db library
end;
except
on E: Exception do begin
// log exception, something went wrong!!
end;
end;
end;
在此线程中创建和销毁数据库连接非常重要,否则您将遇到问题......
所以,让我们开始一个db优化线程
...
var
LConnSettings: TConnectionSettings;
// you may want a private TDBOptimizationThread variable rather than
// a variable in a method, but I leave that to you
LDBOptimizationThread: TDBOptimizationThread;
begin
LConnSettings.Database := 'MyDatabase';
LConnSettings.Port := 1234;
LConnSettings.Server := 'localhost';
// continue with connection settings...
LDBOptimizationThread := TDBOptimizationThread.Create(LConnSettings);
LDBOptimizationThread.Start; // start it
end;
你当然可以把它作为一个低优先级,但如果你的查询每次都不会运行超过几秒钟,我没有看到这个原因,但可以随意反驳。
答案 2 :(得分:0)
恕我直言,低优先级线程是实现此类任务的方法。但是您不必为每个优化例程创建不同的线程,只需要一个线程来处理所有这些线程。因此,您可以更容易地按特定顺序或以不同的频率执行它们,并且您将确保它们不会相互影响(从DB的角度来看)。