在开发服务器端程序的时候,日志是必须的一个功能。由于服务器端的要频繁的把数据写入日志,开始的时候用了一个很简单日志函数
就是直接把日志字符写入文件中。然后关闭连接。一直也应用良好。但做压力测试的时候,因为要每个连接的数据都要写入日志,发现运行的一段时间后,频繁掉线,CPU占用率,居高不下,优化了可以想到的很多地方,有一定的效果,仔细观察发现,硬盘灯狂闪不止,说明硬盘I/0操作过于紧张。但测试的时候,基本是不读写硬盘的,恍然发现,是日志函数影响到整个系统的性能。每一个日志数据的时候,就要打开文件,写入文件,关闭文件。哈,这些都是相对昂贵的I/0操作。优化的方法很简单,缓存数据,定期的批量写入磁盘。基于此设计思路就开发了一个新的日志类。以空间换取时间。
内部采用双缓冲算法,写入信息的时候,是直接写入到 内存中,然后线程根据一定的时间间隔,将内存中的数据写到磁盘文件中,里面开辟了两块缓冲内存队列,采用了生产者===》消费者模式,WriteLog 是写入日志数据,算是数据的生产者,TFileStream对象,将内存中的数据写入磁盘是消费者角色,由于采用了双缓冲方式,减少了生产与消费间的干扰. 提高了性能,减少日志的写入时间。也勉强算是个双缓冲队列的实际应用.
此日志类是基于线程实现的。为了方便使用。内部采用了锁定机制。是线程安全的类。当数据量比较大或者为了便于日志文件的管理
我们会把数据按一定规则生成不同的日志文件名,最常见的就是按日期作日志文件的名称。例如 20110702.log, 20110701.log 等
此日志类中考虑到此情况,可以随时更改日志文件名。
property FileName:string read getLogFileName write setLogFileName; 要修改日志文件名,直接赋值即可。也是线程安全的。
最后要说明下,此日志类的设计思路也可以用于其它方面。缓冲,空间换时间是软件设计中常用的方法。
//实现的代码
unit uSfLog;
interface
uses
Windows, Messages, SysUtils, Variants, Classes;
type
TsfLog=class(TThread)
private
FLF:string;//#13#10;
FS:TFileStream;
FCurFileName:string;
FFileName:string;
FBegCount:DWord;
FBuffA,FBuffB:TMemoryStream;
FCS:TRTLCriticalSection;
FCS_FileName:TRTLCriticalSection;
FLogBuff:TMemoryStream;
procedure WriteToFile();
function getLogFileName: string;
procedure setLogFileName(const Value: string);
protected
procedure Execute();override;
public
constr