总结了一些经验,现贴出于大家讨论。 1、构件的使用 开始我一直使用Indy,但最近在开发一个100-350并发用户的服务器端时发现了Indy问题,由于用户的访问非常繁重,服务器工作两周后出现了70多的废连接。导致服务器响应变的慢。而且我观察到有时INDY能自动释放这些废连接,有时多到200多都不释放。后来我改DXSock 3.0构件,代码没有作任何改动,服务从6月1日到今天没有重启一次而且没有一个废连接, 我花了一周看DXSock的代码,改了些错误,也学习了很多,DXSock构成思想很好。它的连接响应线程不是动态创建的,而是你设置多少就一次性创建多少。节省了创建、释放的大量时间。 所以再开发服务器端软件我推进使用DXSOCK构件。
2、数据库使用 很多朋友在讨论多线程中使用数据库的问题,这在 络服务器开发中这是常常需要考虑的问题,很多朋友都采用一个线程建立一个数据库的连接,我认为这种方法在小规模、小并发应用中是可以的,但是一旦负荷上去、并发一多这样就很多问题了,比如资源消耗(数据库)、时间消耗。这种方式我用过,结果是运行一段时间后数据库再也连接不上了。 我再这方面有两个解决办法: a、采用ASTA构件的方法,根据分析负荷一次性创建一个ADOCONNEC连接池,靠一个同步模块来管理,客户端请求-》构造SQL-》让同步管理模块来分配一个ADOCONNECT联机-》执行SQL,返回结果,如果这时ADOCONNECT满,此SQL等待。代码如下: b、对于不需要实时返回数据库信息的应用,客户端请求来-》服务器创建SQL语句和一个TAG-》SQL语句送入队列,然后一条一条的执行,TAG返回客户端,过一段时间客户端再通过这个TAG来服务端获得结果。 ********************************************队列管理代码*********************** Unit uitQueueManage;
Interface
Uses Windows, Messages, SysUtils, Variants, Classes, Contnrs;
Type TSyncManage = Class(TObject) Protected FHandle: THandle; Public Property Handle: THandle Read FHandle; Constructor Create(Const Name: String; InitCount, MaxBuffer: Integer); Destructor Destroy; Override; Function Release: Boolean; Overload; Function WaitFor(TimeOut: Integer): Boolean; End;
Type PQueueItem = ^TQueueItem; TQueueItem = Record FRequestCount: Integer; FCommand: Integer; FDataStr: String; FDataInt: Integer; FDataBool: Boolean; End; TProgressEvent = Procedure(Sender: TObject; aQueueItem: TQueueItem) Of Object; TQueueManage = Class(TObject) Private FQueue: TQueue; FSyncManage: TSyncManage; FOnProgress: TProgressEvent; FLock: TRTLCriticalSection; Public Constructor Create(aQueueName: String; aBuffer: Integer); Destructor Destroy; Override; Procedure PushQueue(aQueueItem: TQueueItem); Published Property OnProgress: TProgressEvent Read FOnProgress Write FOnProgress; End;
Type TQueueThread = Class(TThread) Private hSyncManage: TSyncManage; hOwner: TQueueManage; hQueue: TQueue; Procedure DoProgress; Protected Procedure Execute; Override; Public Constructor Create(aOwner: TQueueManage; aQueue: TQueue; aSyncManage: TSyncManage); Virtual; End;
Implementation
//***********************************************************TSyncThread**************************
Constructor TSyncManage.Create(Const Name: String; InitCount, MaxBuffer: Integer); Begin FHandle := CreateSemaphore(Nil, InitCount, MaxBuffer, Pchar(Name)); If FHandle = 0 Then abort; End;
Destructor TSyncManage.Destroy; Begin If FHandle <> 0 Then CloseHandle(FHandle); End;
Function TSyncManage.WaitFor(TimeOut: Integer): Boolean; Begin Result := WaitForSingleObject(FHandle, TimeOut) = WAIT_OBJECT_0; End;
Function TSyncManage.Release: Boolean; Begin Result := ReleaseSemaphore(FHandle, 1, Nil); End;
//***********************************************************TQueueThread**************************
Constructor TQueueThread.Create(aOwner: TQueueManage; aQueue: TQueue; aSyncManage: TSyncManage); Begin Inherited Create(True); hOwner := aOwner; hQueue := aQueue; hSyncManage := aSyncManage; Priority := tpHigher; Resume; End;
Procedure TQueueThread.Execute; Begin While Not Terminated Do Begin hSyncManage.WaitFor(Integer(INFINITE)); //无限等 If Terminated Then Exit; DoProgress; End; End;
Procedure TQueueThread.DoProgress; Var mQueueItem: PQueueItem; Begin mQueueItem := hQueue.Pop; If Assigned(hOwner.FOnProgress) Then hOwner.FOnProgress(hOwner, mQueueItem^); Dispose(mQueueItem); End;
//***********************************************************TQueueManage*************************
Var FQueueThread: TQueueThread;
Constructor TQueueManage.Create(aQueueName: String; aBuffer: Integer); Begin Inherited Create; InitializeCriticalSection(FLock); FQueue := TObjectQueue.Create; FSyncManage := TSyncManage.Create(aQueueName, 0, aBuffer); //缓冲区大小 FQueueThread := TQueueThread.Create(Self, FQueue, FSyncManage); End;
Destructor TQueueManage.Destroy; Begin EnterCriticalSection(FLock); Try FQueueThread.Terminate; FSyncManage.Release; FreeAndNil(FQueueThread); FreeAndNil(FSyncManage); FreeAndNil(FQueue); Inherited Destroy; Finally LeaveCriticalSection(FLock); DeleteCriticalSection(FLock); End; End;
Procedure TQueueManage.PushQueue(aQueueItem: TQueueItem); Var mQueueItem: PQueueItem; Begin New(mQueueItem); mQueueItem^ := aQueueItem; EnterCriticalSection(FLock); FQueue.Push(mQueueItem); LeaveCriticalSection(FLock); FSyncManage.Release; End;
End. ********************************************队列管理代码*********************** ADO连接同步管理我稍后放上来,欢迎大家讨论。 来自: chenshaizi, 时间:2003-12-8 20:58:00, ID:2342117 学习ing 来自: guilinxie, 时间:2003-12-8 21:12:00, ID:2342139 这样的贴子很有学习意义。 UP 来自: fjjb, 时间:2003-12-8 22:03:00, ID:2342226 学习,期待ADO连接同步管理 来自: tongdanfeng, 时间:2003-12-9 9:16:00, ID:2342528 什么地方有DXSock .30下载 来自: 唐佐平, 时间:2003-12-9 9:28:00, ID:2342571 很好,谢谢了! 来自: QSmile, 时间:2003-12-9 9:52:00, ID:2342663 什么地方有DXSock .30下载
楼主真他妈是个好人。 我选楼主为 2003年大富翁杰出青年 来自: strgold, 时间:2003-12-9 10:22:00, ID:2342766 kl 来自: kkg, 时间:2003-12-9 10:46:00, ID:2342839 顶/// 来自: 张无忌, 时间:2003-12-9 12:37:00, ID:2343217 呵呵,200~300个连接压力不够哦,DXSocket也就一般, 而且DELPHI自己的TQueue类效率很低,我自己改写了一个速度比他快8倍,看来 做服务器程序最好都自己从头写,用现成的始终不是最好的解决方法,而且用别 人的破戒的东西有偷盗之嫌。 来自: lynu, 时间:2003-12-9 12:45:00, ID:2343250 很不错. 当然大一点的系统,建议还是不要用长连接,这样多数系统能服务的客户端就可以高出很多,一般的系统并发机率可能只有5-15%,我想很少会有系统超过30%以上.不过非长连接的话就要考虑维护会话状态的成本. indy中大量使用类似如下的代码 ms := TMemorystream.create; ms.write(….)… 这些是很没效率的,如果不为TMemorystream一次性分配足够空间,那么TMemorystream在分配的空间不够用的时候,就需要重新分配,这是一个极没效率的操作.频繁的重新分配,拷贝原数据等,使得TMemorystream在某些时间甚至比硬盘读写都要慢几倍.所以用indy的话就要分析一下系统的实际情况了.
来自: element, 时间:2003-12-9 12:47:00, ID:2343256 一切都为了最求快,一切都要自己写,那就失去使用DELPHI的意义了。 服务器实际负荷=并发数*4.3。 来自: pingshx, 时间:2003-12-9 12:47:00, ID:2343258 楼上的你能否你写的Query给我学习,pingshx@163.com ,THX 楼住能否发你用的DXSocket给我,THX! 来自: 张无忌, 时间:2003-12-9 12:49:00, ID:2343262 DELPHI一样可以从头来做的,只要你有耐心。 来自: 张无忌, 时间:2003-12-9 12:51:00, ID:2343268 element: 你这话我听很多用VC的这么说,他们的意思就是DELPHI只能做一般的普通应用, 难的都要VC做。 来自: element, 时间:2003-12-9 12:51:00, ID:2343269 ADO连接同步管理代码,我是从应用中剥离出来的,对不起不能提供全部。供大家讨论 Unit uitSyncConnect;
Interface
Uses Windows, Messages, SysUtils, Variants, Classes, Contnrs, Activex, ADODB, DB;
Const csMaxQueueThread = 9;
Type TSyncManage = Class(TObject) Protected FHandle: THandle; Public Property Handle: THandle Read FHandle; Constructor Create(Const Name: String; InitCount, MaxBuffer: Integer); Destructor Destroy; Override; Function Release: Boolean; Overload; Function WaitFor(TimeOut: Integer): Boolean; End;
Type PQueueItem = ^TQueueItem; TQueueItem = Record rThreadTag: Integer; rEvent: THandle; rADOQuery: TADOQuery; rIsCommand: Boolean; rIsError: Boolean; rMessage: String[255]; End; TSyncConnect = Class(TObject) Private FThreadCount: Integer; FQueue: TQueue; FSyncManage: TSyncManage; FLock: TRTLCriticalSection; Public Constructor Create(Const aQueueName: String; Const aConnectStr: String; Const aBuffer: Integer = 1024; Const aThreadCount: Integer = 5); Destructor Destroy; Override; Procedure PushQueue(Var aQueueItem: TQueueItem); Published
End;
Type TQueueThread = Class(TThread) Private hSyncManage: TSyncManage; hQueue: TQueue; hTag: Integer; hADOConnect: TADOConnection; Protected Procedure Execute; Override; Public Constructor Create(Const aConnStr: String; Const aTag: Integer; aQueue: TQueue; aSyncManage: TSyncManage); Virtual; Destructor Destroy; Override; End;
Implementation
//***********************************************************TSyncThread**************************
Constructor TSyncManage.Create(Const Name: String; InitCount, MaxBuffer: Integer); Begin FHandle := CreateSemaphore(Nil, InitCount, MaxBuffer, PChar(Name)); If FHandle = 0 Then abort; End;
Destructor TSyncManage.Destroy; Begin If FHandle <> 0 Then CloseHandle(FHandle); End;
Function TSyncManage.WaitFor(TimeOut: Integer): Boolean; Begin Result := WaitForSingleObject(FHandle, TimeOut) = WAIT_OBJECT_0; End;
Function TSyncManage.Release: Boolean; Begin Result := ReleaseSemaphore(FHandle, 1, Nil); End;
//***********************************************************TQueueThread**************************
Constructor TQueueThread.Create(Const aConnStr: String; Const aTag: Integer; aQueue: TQueue; aSyncManage: TSyncManage); Begin Inherited Create(True); hQueue := aQueue; hSyncManage := aSyncManage; Priority := tpHigher; hADOConnect := TADOConnection.Create(Nil); hADOConnect.ConnectionString := aConnStr; hTag := aTag; Resume; End;
Destructor TQueueThread.Destroy; Begin Terminate; WaitFor; FreeAndNil(hADOConnect); Inherited Destroy; End;
Procedure TQueueThread.Execute; Var mQueueItem: PQueueItem; Begin While Not Terminated Do Begin hSyncManage.WaitFor(Integer(INFINITE)); //μè If Terminated Then Exit; If hQueue.Count <= 0 Then Exit; mQueueItem := hQueue.Pop; mQueueItem.rThreadTag := hTag;
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!
|