小弟负责公司为铁道部开发的火车实时定位查询系统(类似于GPS定位,不过我们不用GPS设备,比他们的功能强大),车载系统每5秒要向地面服务器发送数据包,地面的通讯服务器负责接收数据并将数据发送给数据服务器对数据进行解析处理,数据服务器将解析后的数据包发给查询终端软件,查询终端软件接收数据服务器发来的数据包,并根据数据包里的公里标等信息在地图上进行动态的自动定位。现在铁道部领导要求是普通的PC上能够同时支持5000辆车(在5秒的时间间隔内)。所以,对在地图中进行定位的查找算法显得尤为重要。
    在此,我要先声明一点的是,公司前期的版本在车载系统发给地面的通信服务器,通信服务器发给数据服务器后,数据服务器要将实时信息进行入库(Oracle),由于在线火车的增多,由于数据库要战胜很大的内存,数据服务器写库在5秒的时间间隔内,很难全部处理完,所以,我们就取消了实时信息入库的处理,通过内存传递的方式将实时信息传递到查询终端。我因此专门为公司开发一套适合在铁路行业使用的GIS平台,支持地图的放大缩小、漫游以及投影等操作,数据直接存储到内存流中,并可以保存到地图文件中(支持图层,可以单个图层存为一个文件,也可以一个文件存储所有的图层)。
   后来,铁道部要求在GIS中支持信号机(即实际的铁路线路上是每隔大约一千米有一个信号机,火车的行车是根据信号机来进行控制的,红灯停车,绿灯通过,黄灯限速等),我的GIS地图的结构是这样的:一条铁路线路上可以包括多种结点(车站及信号机以及一个经纬度点),通过这种结构来解决当地图放大到一定的程度后,车站就偏离线路的问题(在绘制线路时,线路对象是车站对象信号机对象的父类,他们之间是一对多的关系,即一条线路上可以有多个车站与信号机),枢纽车站(即在此车站需要线路转弯的)通过类似于Visio中的热链接来实现(即一个枢纽车站可以热链接多个线路)可以将多条线路链接到一起,从而整个的形成一张有序的有方向的(火车的行驶是有方向的,上行下行)网状结构。
    现在全国的车站与信号机都做出来了,大约有八千个车站左右,信号机有4万左右。为提高搜索的算法速度,我在地图文件打开后就自动建立一个有关车站的有序序列,通过二分查找算法来对车站进行搜索(定位一个火车的所在位置需要搜索当前的TMIS车站号以及下一个站的TMIS车站号,再根据公里标实现将其定位到两个车站之间。),二分法比直接遍历的方法要快很多。现在在我的程序下已经可以支持到近5000辆同时在线火车的,该系统已经推广到全国的七个铁路局及站段使用。
    我现在想再次的来提高查找的速度,并想通过使用多线程方式来解决,当用户点击“漫游(即移动地图)”时,查询终端能够马上有所反应,由于当前的对数据服务器传来的实时信息(比如传来一个动态数组,每个数组的内容是一个在线机车的结构,我是通过for循环来进行处理的,而随着在线火车的增多,这分明是需要很多的时间的)。
    我想与大家在此讨论一种更快的实现算法,以及如何通过多线程将现在的主线程进行的工作进行合理的分配,以达到提高速度的意愿。
    我现在已经将地图做成了控件,也有这方面的测试程序,哪位高人有兴趣,我愿意提供,敬请多提宝贵修改意见!
    TCADOnlineEngine是负责管理多个在线机车的类,TCADSingleEngine是单个在线机车的动态定位及提供火车在地图上进行动态闪耀的实现类。
    当从数据服务器接收到在线机车的数据包后,将调用TCADOnlineEngine类的Execute方法,如下:
    procedure TCADOnlineEngine.Execute;
var
    I: Integer;
    Eng: TCADSingleEngine;
begin
    if (Active) then
    begin
        for I := 0 to EngineCount - 1 do
        begin
            Eng := Engines[I];
            if Eng <> nil then
                Eng.Execute;
        end;
    end
    else
        if EngineCount = 0 then
        Owner.Invalidate;
end;
    从而启动单个在线机车的处理方法,发下:
    procedure TCADSingleEngine.Execute;
var
    AP: TCADActivePosition;
    bCan: Boolean;
begin
    bCan := Active;
    InitDrawData;//对要进行绘制的数据进行初始化!
    if bCan then
    begin
        InitLocateData(FLocationInfo);//初始化定位的数据
        AP := Owner.Owner.GetActivePosition(FLocationInfo);//在此方法内有查找及定位的二分算法
        FLocationResult := AP.Result;
        if FLocationResult then
        begin
            FActiveLineColor := AP.ActiveLineColor;
            case TrainDirection of
                tdUpDirection: LocateRealPoint := AP.UpDirectionPoint;//调用此属性可以启动Paint方法
                tdDownDirection: LocateRealPoint := AP.DownDirectionPoint;;//调用此属性可以启动Paint方法            end;
        end;
    end;
end;    二分查找算法如下:
function TCADCustomDraw.DichotomySearchTMISCode(
    ATMISCode: Integer): TCADStationIndexInfo;
var
    iLow, iHigh, iMid, iCnt, K: Integer;
    DStaIndex: TCADStationIndexInfo;
begin
    iLow := 0;
    iCnt := GetStationIndexCount;
    iHigh := iCnt - 1;    K := 0;    FillChar(Result, SizeOf(Result), 0);    while (iLow <= iHigh) do
    begin
        iMid := (iHigh + iLow) div 2;
        DStaIndex := InternalGetStationIndexInfo(iMid);
        if DStaIndex.TMISCode = ATMISCode then
        begin
            Result := DStaIndex;
            Break;
        end
        else
        begin
            if (ATMISCode > DStaIndex.TMISCode) then
                iLow := iMid + 1
            else
                iHigh := iMid - 1;
        end;
        Inc(K);
    end;
end;
    欢迎高手提出更宝贵的查找算法,以及如何通过线程来分担主线程for循环的压力!
    欢迎做实时系统的同行或者GIS方面的同行与我共同讨论,得到大家的帮助是我的荣幸!