是否有一个通用的;对象池“;Delphi的实现?
我在为Delphi寻找数据库连接池实现时遇到了这个问题 对象池需要两种方法:是否有一个通用的;对象池“;Delphi的实现?,delphi,oop,delphi-2009,pool,Delphi,Oop,Delphi 2009,Pool,我在为Delphi寻找数据库连接池实现时遇到了这个问题 对象池需要两种方法: get-要从池中获取对象(如果池为空或其大小未达到最大大小,则将创建一个新实例),此方法必须是线程安全的,以便两个线程不能同时获取一个对象。如果所有对象都在使用中,get方法必须阻塞(可能带有可选的超时) put-将对象释放(返回)到池中 所以用例看起来像 O := Pool.Get; try ... use O finally Pool.Put(O); end; 更新:添加了Delphi 2009标记s
- get-要从池中获取对象(如果池为空或其大小未达到最大大小,则将创建一个新实例),此方法必须是线程安全的,以便两个线程不能同时获取一个对象。如果所有对象都在使用中,get方法必须阻塞(可能带有可选的超时)
- put-将对象释放(返回)到池中
O := Pool.Get;
try
... use O
finally
Pool.Put(O);
end;
更新:添加了Delphi 2009标记so泛型。集合和TMonitor可能是实现的一部分根据用于在多个线程上执行任务或作业的(线程)平台或体系结构,处理数据库连接的“泛型”方法是使用
threadvar
和每个线程的数据库连接。如果您有线程池或线程管理器,则应将其扩展为在添加线程时启动DB连接(或在线程上运行的第一个任务时连接到DB),并在销毁线程时关闭数据库连接。否Delphi中没有通用对象池。您必须使用自己的代码,或者使用第三方代码,例如:这里:TMonitor
在Delphi-2009中严重损坏。它在Delphi-XE2 upd 4中起到了作用,这里的答案是基于Delphi-XE2 upd 4(或更新版本)
这里,对象池基于线程安全的TThreadedQueue
创建池对象的机制内置于线程安全机制中。
从池中获取对象是线程安全的,并且在创建池时定义了超时。
队列大小也在池创建时定义,其中还传递了用于对象创建的回调例程
uses
System.Classes,Generics.Collections,System.SyncObjs,System.Diagnostics;
type
TObjectConstructor = function : TObject;
TMyPool = Class
private
FQueueSize,FAllocatedObjects : integer;
FGetTimeOut : Integer;
FQueue : TThreadedQueue<TObject>;
FObjectConstructor : TObjectConstructor;
FCS : TCriticalSection;
function AllocateNewObject : TObject;
public
Constructor Create( AnObjectConstructor : TObjectConstructor;
QueueSize : Integer;
GetTimeOut : Integer);
Destructor Destroy; override;
procedure Put( const AnObject : TObject);
function Get( var AnObject : TObject) : TWaitResult;
End;
function TMyPool.AllocateNewObject: TObject;
begin
FCS.Enter;
Try
if Assigned(FObjectConstructor) and
(FAllocatedObjects < FQueueSize)
then
begin
Inc(FAllocatedObjects);
Result := FObjectConstructor;
end
else
Result := Nil;
Finally
FCS.Leave;
End;
end;
constructor TMyPool.Create( AnObjectConstructor : TObjectConstructor;
QueueSize : Integer;
GetTimeOut : Integer);
begin
Inherited Create;
FCS := TCriticalSection.Create;
FAllocatedObjects := 0;
FQueueSize := QueueSize;
FObjectConstructor := AnObjectConstructor;
FGetTimeOut := GetTimeOut;
FQueue := TThreadedQueue<TObject>.Create(FQueueSize+1,Infinite,10);
// Adding an extra position in queue to safely remove all items on destroy
end;
destructor TMyPool.Destroy;
var
AQueueSize : integer;
AnObject : TObject;
wr : TWaitResult;
begin
FQueue.PushItem(Nil); // Just to make sure we have an item in queue
repeat // Free objects in queue
AnObject := nil;
wr := FQueue.PopItem(AQueueSize,AnObject);
if (wr = wrSignaled) then
AnObject.Free;
until (AQueueSize = 0);
FQueue.Free;
FCS.Free;
Inherited;
end;
function TMyPool.Get(var AnObject: TObject) : TWaitResult;
var
sw : TStopWatch;
begin
AnObject := nil;
// If queue is empty, and not filled with enough objects, create a new.
sw := TStopWatch.Create;
repeat
sw.Start;
Result := FQueue.PopItem( AnObject); // Timeout = 10 ms
if (Result = wrTimeOut) and
(FAllocatedObjects < FQueueSize) and
Assigned(FObjectConstructor)
then begin // See if a new object can be allocated
AnObject := Self.AllocateNewObject;
if Assigned(AnObject) then
begin
Result := wrSignaled;
Exit;
end;
end;
sw.Stop;
until (Result = wrSignaled) or (sw.ElapsedMilliseconds > FGetTimeOut);
end;
procedure TMyPool.Put( const AnObject: TObject);
begin
FQueue.PushItem(AnObject); // Put object back into queue
end;
以及如何使用的示例:
var
AnObject : TObject;
MyObject : TMyObject;
wr : TWaitResult;
begin
wr := MyObjPool.Get(AnObject);
if (wr = wrSignaled) then
begin
MyObject := TMyObject(AnObject);
try
// Do something with MyObject
finally
MyObjPool.Put(AnObject);
end;
end;
end
今天刚刚遇到Eric,他是dwScript的现任开发者。有一个对象池实现,我还没有尝试过,但是你知道,Delphi社区的人知道Spring4D是高质量的:)
似乎没有文档,但它有泛型的泛型方法?您针对的是哪个版本的Delphi?@ArnaudBouchez添加了Delphi 2009标记(泛型在这个版本中不起作用,但稍后可能会是另一个主题)@SirRufo yes泛型肯定能让它更具吸引力。D2009和XE TMonitor有可用的补丁(请参阅)。请注意,TMonitor中有两个错误。当多个消费者打到一个空队列时,它会露出丑陋的面孔。我想这就是@gabr上显示的补丁所纠正的。另一个错误在多个使用者访问一个完整队列时出现。有关这些条件的测试,请参阅。在XE2 upd 4之前,我使用了一个稍微修改过的队列,而不是TThreadedQueue。非常感谢TMonitor中第二个严重问题的指针。至少在Delphi 2009中它能与一个消费者合作,总比什么都没有好;)“delphipooling”unicode准备好了吗?它可以在Delphi XE中使用吗?
var
AnObject : TObject;
MyObject : TMyObject;
wr : TWaitResult;
begin
wr := MyObjPool.Get(AnObject);
if (wr = wrSignaled) then
begin
MyObject := TMyObject(AnObject);
try
// Do something with MyObject
finally
MyObjPool.Put(AnObject);
end;
end;
end