上周给一个网友优化程序,修改了他的数据库结构,使速度提高了20%。

时间:2022-10-06 20:37:01

上周给一个网友优化程序,修改了他的数据库结构,使速度提高了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   :=   &apos;udp &apos;;
                WSocket.Addr   :=   &apos;127.0.0.1 &apos;;
                WSocket.Port   :=   &apos;1001 &apos;;
                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   :=   &apos;我爱啃猪脚   我爱啃猪脚 &apos;;
    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   :=   &apos; &apos;;
                                    end
                                else
                                    begin
                                        if   ACol   =   1   then
                                            s   :=   IntToStr(testlist[idx].sentCount)
                                        else
                                            begin
                                                s   :=   FormatFloat( &apos;0.000 &apos;,   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( &apos;0.000 &apos;,   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)   +   &apos;.dat &apos;;
    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.