上周给一个网友优化程序,修改了他的数据库结构,使速度提高了20%。说起来这个网友也是在csdn上认识的。当时是在这个这个帖子认识的(http://topic.csdn.net/u/20070409/11/ce994716-2fb2-495d-91d8-79e0b6aba0fd.html)。
通讯协议:UDP
通讯架构:车----- >服务器---- >客户中心
【汽车】向【服务器】发数据,【服务器】收到数据后处理,在发送给【客户中心】
1、有2万辆汽车,每辆平均一分钟向服务气发送四条数据,也就是说服务一分钟内收到8万条数据。
2、服务器处理一条数据的平均时间,大约10毫秒,也就是说一分大约处理6000条数据(包括处理完后发送给【客户中心】)。
3、引发问题:由如服务器处理速度慢于接收速度,就引发大量数据丢失。
4、我的解决方案是:服务器收到数据后,不进行处理,把数据放到一个数据缓冲区里面(这样可以保证数据不被丢失),在采取多线程处理数据,设想如果一个线程一分钟能处理六千条,四个处理线程就可以搞定,但是发现多个线程处理,在单CPU的情况比一个线程处理好像还好慢,个人估计是由如线程之间同学协调,和线程切换引起。这样就引起另一个情况,由如处理速度,没有提升上来,数据缓冲区将不断增加,最后引起内存不够,而死掉。
对以上情况现在求解决方案:
解决方案前提:不加增加服务器数量(服务器是IBM的专用服务器)。
解决后重谢!如果有兴趣可以加本人QQ讨论也可以,QQ:63731429。
我给他写了我的udp测试程序可以做到每分钟大约30万到50万的条数据(同时存成文件了)。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, WSocket, ExtCtrls, Grids, StdCtrls;
const
BlockSize = 32;
type
TtestThread = class(TThread)
private
idx: Integer;
Fid: integer;
FsentCount: Integer;
FbeginTime: DWORD;
buff: array[0..BlockSize - 1] of Char;
WSocket: TWSocket;
procedure makeBuff;
procedure WriteIdx;
protected
procedure Execute; override;
public
constructor Create(Id: Integer);
destructor Destroy; override;
property sentCount: integer read FsentCount;
property beginTime: DWORD read FbeginTime;
end;
TForm1 = class(TForm)
Panel1: TPanel;
Panel2: TPanel;
StringGrid1: TStringGrid;
Timer1: TTimer;
Button1: TButton;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
procedure Timer1Timer(Sender: TObject);
private
FbeginTime: DWORD;
testlist: array of TtestThread;
procedure cleartestList;
procedure addTest(count: integer);
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.addTest(count: integer);
var
i: integer;
begin
cleartestList;
SetLength(testlist, count);
for i := low(testlist) to high(testlist) do
testlist[i] := TtestThread.Create(i);
StringGrid1.RowCount := count + 1;
end;
procedure TForm1.cleartestList;
var
i: integer;
begin
for i := low(testlist) to high(testlist) do
testlist[i].Terminate;
for i := low(testlist) to high(testlist) do
testlist[i].WaitFor;
for i := low(testlist) to high(testlist) do
testlist[i].Free;
SetLength(testlist, 0);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
StringGrid1.DoubleBuffered := true;
StringGrid1.Cells[0, 0] := '序号 ';
StringGrid1.Cells[1, 0] := '发送包数 ';
StringGrid1.Cells[2, 0] := '发送包数/秒 ';
FbeginTime := GetTickCount;
addTest(30);
end;
{ TtestThread }
constructor TtestThread.Create(Id: Integer);
begin
idx := 0;
FsentCount := 0;
Fid := Id;
makeBuff;
FbeginTime := GetTickCount;
WSocket := nil;
FreeOnTerminate := false;
inherited Create(False);
end;
destructor TtestThread.Destroy;
begin
if WSocket < > nil then
WSocket.Free;
inherited;
end;
procedure TtestThread.Execute;
var
i: integer;
begin
WSocket := TWSocket.Create(nil);
while not Terminated do
begin
try
for i := 1 to 10 do
begin
Sleep(10);
if Terminated then
Break;
end;
if Terminated then
Break;
WSocket.Proto := 'udp ';
WSocket.Addr := '127.0.0.1 ';
WSocket.Port := '1001 ';
WSocket.LocalPort := IntToStr(2000 + fId); WSocket.Connect;
for i := 1 to 20 do
begin
inc(idx);
WriteIdx;
WSocket.Send(@(buff[0]), BlockSize);
inc(FsentCount)
end;
WSocket.Close;
except
end;
end;
end;
procedure TtestThread.makeBuff;
var
s: string;
begin
FillChar(buff[0], BlockSize, 0);
buff[0] := #02;
buff[BlockSize - 1] := #03;
Move(fid, buff[1], 4);
Move(idx, buff[5], 4);
s := '我爱啃猪脚 我爱啃猪脚 ';
Move(s[1], buff[9], length(s));
end;
procedure TtestThread.WriteIdx;
begin
Move(idx, buff[5], 4);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
close;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
Timer1.Enabled := false;
cleartestList;
end;
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
var
idx: Integer;
bcolor, fcolor: TColor;
s: string;
begin
if gdSelected in State then
begin
bcolor := clHighlight;
fcolor := clHighlightText
end
else
if gdFixed in State then
begin
bcolor := clBtnFace;
fcolor := clWindowText;
end
else
begin
bcolor := clWhite;
fcolor := clWindowText;
end;
with StringGrid1 do
begin
Canvas.Brush.Color := bcolor;
Canvas.Font.Color := fcolor;
Canvas.FillRect(Rect);
if ARow = 0 then
s := Cells[acol, arow]
else
begin
case ACol of
0: s := IntToStr(ARow);
1, 2:
begin
idx := ARow - 1;
if idx > high(testlist) then
begin
s := ' ';
end
else
begin
if ACol = 1 then
s := IntToStr(testlist[idx].sentCount)
else
begin
s := FormatFloat( '0.000 ', testlist[idx].sentCount * 1000 / (10 + gettickcount - testlist[idx].begintime));
end;
end;
end;
end;
end;
DrawText(Canvas.Handle, pchar(s), -1, Rect, DT_CENTER or DT_SINGLELINE or DT_VCENTER);
end;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
i, c: integer;
begin
Timer1.Enabled := false;
StringGrid1.Repaint;
c := 0;
for i := low(testlist) to high(testlist) do
inc(c, testlist[i].sentCount);
Label2.Caption := IntToStr(c);
Label4.Caption := FormatFloat( '0.000 ', c * 1000 / (10 + gettickcount - Fbegintime));
Timer1.Enabled := true;
end;
end.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, WSocket, ExtCtrls, WinSock, StdCtrls;
const
BuffSize = 1024 * 512;
BlockSize = 32;
type
TForm1 = class(TForm)
WSocket: TWSocket;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Timer1: TTimer;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
Label8: TLabel;
procedure FormCreate(Sender: TObject);
procedure WSocketDataAvailable(Sender: TObject; Error: Word);
procedure Timer1Timer(Sender: TObject);
private
buff_Idx: integer;
buff: array[0..BuffSize] of Byte;
ReceiveCount: Integer;
ErrCount: Integer;
LastTime: DWORD;
LastReceiveCount: Integer;
procedure saveFile;
public
end;
var
Form1: TForm1;
path: string;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
ReceiveCount := 0;
ErrCount := 0;
buff_Idx := 0;
LastTime := 0;
LastReceiveCount := 0;
WSocket.Listen;
end;
procedure TForm1.saveFile;
var
fn: string;
fs: TFileStream;
begin
fn := path + IntToStr(GetTickCount) + '.dat ';
fs := TFileStream.Create(fn, fmcreate);
fs.WriteBuffer(buff, buff_Idx + 1);
FreeAndNil(fs);
buff_Idx := 0;
end;
procedure TForm1.WSocketDataAvailable(Sender: TObject; Error: Word);
var
Len: Integer;
Src: TSockAddrIn;
SrcLen: Integer;
begin
if buff_Idx > BuffSize - BlockSize then
saveFile;
inc(ReceiveCount);
SrcLen := SizeOf(Src);
Len := WSocket.ReceiveFrom(@(buff[buff_Idx]), BlockSize, Src, SrcLen);
if Len < 0 then
exit;
if Len < > BlockSize then
begin
Inc(ErrCount);
end
else
begin
inc(buff_Idx, BlockSize);
if buff[buff_Idx - 1] < > 3 then
Inc(ErrCount);
end;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
t: DWORD;
i: integer;
begin
Label3.Caption := IntToStr(ReceiveCount);
Label4.Caption := IntToStr(errCount);
t := GetTickCount;
if LastTime > 0 then
begin
i := ReceiveCount - LastReceiveCount;
Label8.Caption := IntToStr(i);
Label7.Caption := IntToStr(i * 60);
end;
LastTime := t;
LastReceiveCount := ReceiveCount;
end;
initialization
path := ExtractFilePath(path);
end.