怎样划分服务器端的Data为苦干部分,以便客户端多线程读取?(100分)

  • 主题发起人 主题发起人 wonken
  • 开始时间 开始时间
W

wonken

Unregistered / Unconfirmed
GUEST, unregistred user!
我在服务器端已取得clientdataset.data提供给客户端使用,但是如何将这个data按记录数分割成苦干部分呢?
 
我自己搞定了,作个通用类再发上来吧。应该支持cmdtxt和providername指定查询.不过不是划分DATA而是在datarequest作了文章,已经调试通过没有问题。有哪位知道如何划分DATA照样结帖给分。
 
详细说说怎么做的吧,我也在客户端用了多线程,在adodataset 上对数据做了区分,但是数据量较大时总是提示数据提供程序或其他服务返回E_FAIL 状态
 
unit DataMain;
{$WARN SYMBOL_PLATFORM OFF}
interface
uses
Windows, Messages, SysUtils, Classes, ComServ, ComObj, VCLCom, DataBkr,
DBClient, GMServer_TLB, StdVcl, DBXpress, FMTBcd, DB, SqlExpr, variants,
ComCtrls, Provider, ADODB, Inifiles, Dialogs ;
type
TGMService = class(TRemoteDataModule, IGMService)
SCCLIENT: TSQLConnection;
ACACT: TADOConnection;
ADOTB_Acts: TADOTable;
DSP_TActs: TDataSetProvider;
SQY_Temp: TSQLQuery;
SQLSP_UserInfo: TSQLStoredProc;
DSP_UserInfo: TDataSetProvider;
SDS_GetDatas: TSQLDataSet;
SQY_DoCmd: TSQLQuery;
CDS_GetDatas: TClientDataSet;
DSP_GetDatas: TDataSetProvider;
CDS_UserInfo: TClientDataSet;
SDS_MultiGet: TSQLDataSet;
DSP_MultiGet: TDataSetProvider;
SDS_1: TSQLDataSet;
DSP_test: TDataSetProvider;
procedure RemoteDataModuleCreate(Sender: TObject);
procedure RemoteDataModuleDestroy(Sender: TObject);
function DSP_GetDatasDataRequest(Sender: TObject;
Input: OleVariant): OleVariant;
function DSP_MultiGetDataRequest(Sender: TObject;
Input: OleVariant): OleVariant;
private
{ Private declarations }
protected
class procedure UpdateRegistry(Register: Boolean;
const ClassID, ProgID: string);
override;
function GetActConn:Boolean;
procedure ConnToAct(const aActName: WideString;
out oError: OleVariant);
safecall;
procedure LogUser(const aUserName, aUserPass: WideString;
out aLogined: OleVariant);
safecall;
procedure GetServerTime(out oTime: OleVariant);
safecall;
procedure AddToList(const aUser, aName, aDept, aLogTime, aHost,
aIP: WideString);
safecall;
procedure DelFromList(const aUser, aIP: WideString);
safecall;
procedure CheckRecord(const aSqlStr: WideString;
out oRecNo,
oError: OleVariant);
safecall;
proceduredo
UserCmd(const aSqlStr: WideString;
aPrepared: OleVariant;
out oSuced, oError: OleVariant);
safecall;
procedure GetCmdDatas(const aSqlStr: WideString;
var vDatas: OleVariant;
out oError: OleVariant);
safecall;
procedure GetUserInfo(const aUserCode: WideString;
out vDatas,
oError: OleVariant);
safecall;
procedure MultiCDSGet(aGetType: Shortint;
const aProviderName: WideString;
abegin
, aGetCount: OleVariant;
out vDatas, oError: OleVariant);
safecall;
public
{ Public declarations }
end;

implementation
uses crypt, ServiceMain, StdCtrls, StrUtils;
{$R *.DFM}
class procedure TGMService.UpdateRegistry(Register: Boolean;
const ClassID, ProgID: string);
begin
if Register then
begin
inherited UpdateRegistry(Register, ClassID, ProgID);
EnableSocketTransport(ClassID);
EnableWebTransport(ClassID);
end else
begin
DisableSocketTransport(ClassID);
DisableWebTransport(ClassID);
inherited UpdateRegistry(Register, ClassID, ProgID);
end;
end;

procedure TGMService.RemoteDataModuleCreate(Sender: TObject);
begin
if not GetActConn then
exit;
frmServiceMain.UpdateLogs(1);
end;

function TGMService.GetActConn: Boolean;
var
myConnStr : string ;
myInifile : Tinifile ;
begin
myInifile := Tinifile.Create(ExtractFilePath(Paramstr(0))+'CSCACT.gml');
try
ACACT.Connected := false ;
myConnStr := myInifile.ReadString('myconnstr','connstr','');
myConnStr := GMDecrypt(myConnStr,135,3);//反加密5次取得正确字符串
ACACT.ConnectionString := myConnStr;
ACACT.Connected := true ;
myInifile.Free;
Result := True;
except
on e:Exceptiondo
begin
Result := False;
myInifile.Free;
ShowMessage(e.Message);
end;
end;
end;

procedure TGMService.ConnToAct(const aActName: WideString;
out oError: OleVariant);
var
LoadStrings,TempStrings:TStrings;
ConnStream:TMemoryStream;
begin
oError := '';
LoadStrings := TStringList.Create;
TempStrings := TStringList.Create;
if SCCLIENT.Connected then
SCCLIENT.Connected:= false ;
SCCLIENT.Params.Clear;
if not(ADOTB_Acts.Active) then
ADOTB_Acts.Open;
ADOTB_Acts.Filter:= 'ActCode='''+aActName+'''';
ADOTB_Acts.Filtered := True;
if ADOTB_Acts.RecordCount>0 then
begin
ConnStream := TMemoryStream.Create;
Tblobfield(ADOTB_Acts.FieldByName('ConnStr')).SaveToStream(ConnStream);
ConnStream.Seek(0,soFrombegin
ning);
LoadStrings.LoadFromStream(ConnStream);
ConnStream.Free;
end;

if DecryptStrings(LoadStrings,TempStrings,135) then
SCCLIENT.Params.Assign(TempStrings) else
exit;
if SCCLIENT.Params.Count>2 then
begin
try
SCCLIENT.Connected := true ;
except
on e:Exceptiondo
oError:=e.Message;
end;
end;
TempStrings.Free;
LoadStrings.Free;
end;

procedure TGMService.LogUser(const aUserName, aUserPass: WideString;
out aLogined: OleVariant);
var
MySql:String;
begin
aLogined := False;
MySql :='select UserCode from A_Users where UserCode='''+aUserName+''' and UserPass='''+aUserPass+'''';
MySql := MySql + ' and Expired=0';
SQY_Temp.Close;
SQY_Temp.SQL.Clear;
SQY_Temp.SQL.Add(MySql);
SQY_Temp.Open;
if SQY_Temp.RecordCount>0 then
aLogined := True else
aLogined := False;
end;

procedure TGMService.GetServerTime(out oTime: OleVariant);
begin
SQY_Temp.Close;
SQY_Temp.SQL.Clear;
SQY_Temp.SQL.Add('select aTime = getDate()');
SQY_Temp.Open;
oTime := SQY_Temp.Fields[0].AsString;
SQY_Temp.Close;
end;

procedure TGMService.AddToList(const aUser, aName, aDept, aLogTime, aHost,
aIP: WideString);
var
aLstItem: TListItem;
begin
with frmServiceMaindo
begin
aLstItem := LstView_Users.Items.Add;
aLstItem.Caption := aUser;
aLstItem.SubItems.Add(aName);
aLstItem.SubItems.Add(aDept);
aLstItem.SubItems.Add(aLogTime);
aLstItem.SubItems.Add(aHost);
aLstItem.SubItems.Add(aIP);
end;
end;

procedure TGMService.DelFromList(const aUser, aIP: WideString);
var
i: integer;
begin
with frmServiceMaindo
begin
for i := 0 to LstView_Users.Items.Count - 1do
begin
if (Trim(LstView_Users.Items.Item.Caption) = Trim(aUser)) and
(Trim(LstView_Users.Items.Item.SubItems[4]) = Trim(aIP))
then
begin
LstView_Users.Items.Delete(i);
end;
end;
end;
end;

procedure TGMService.CheckRecord(const aSqlStr: WideString;
out oRecNo,
oError: OleVariant);
begin
try
SQY_Temp.Close;
SQY_Temp.SQL.Clear;
SQY_Temp.SQL.Add(aSqlStr);
SQY_Temp.Open;
if Not(SQY_Temp.IsEmpty) then
oRecNo := SQY_Temp.RecordCount
else
oRecNo := 0;
except
on e:Exceptiondo
begin
oRecNo := 0;
oError := e.Message;
end;
end;
end;

procedure TGMService.DoUserCmd(const aSqlStr: WideString;
aPrepared: OleVariant;
out oSuced, oError: OleVariant);
begin
oSuced := False ;
if not(SCCLIENT.Connected) then
SCCLIENT.Connected:=True;
try
with SQY_DoCmddo
begin
Close;
SQL.Clear ;
SQL.Add(aSqlStr);
ExecSQL(aPrepared);
Close;
end;
oSuced := True ;
except
on e:Exceptiondo
oError := e.Message;
end;
end;

procedure TGMService.GetCmdDatas(const aSqlStr: WideString;
var vDatas: OleVariant;
out oError: OleVariant);
begin
try
try
CDS_GetDatas.Close;
CDS_GetDatas.CommandText := aSqlStr ;
CDS_GetDatas.Open;
vDatas := CDS_GetDatas.Data;
finally
CDS_GetDatas.Active := False;
end;
except
on e:Exceptiondo
oError := e.Message;
end;
end;

procedure TGMService.GetUserInfo(const aUserCode: WideString;
out vDatas,
oError: OleVariant);
begin
try
try
CDS_UserInfo.Close;
CDS_UserInfo.FetchParams ;
CDS_UserInfo.Params.ParamByName('@UserCode').AsString := aUserCode ;
CDS_UserInfo.Open ;
vDatas := CDS_UserInfo.Data;
finally
CDS_UserInfo.Active := False;
end;
except
on e:Exceptiondo
oError := e.Message;
end;
end;

procedure TGMService.RemoteDataModuleDestroy(Sender: TObject);
begin
frmServiceMain.UpdateLogs(-1);
end;

function TGMService.DSP_GetDatasDataRequest(Sender: TObject;
Input: OleVariant): OleVariant;
var
RecsOut:Integer;
begin
if VarIsArray(Input) then
begin
with Sender as TDataSetProviderdo
begin
if Input[0]=0 then
begin
with TSQLDataSet(DSP_GetDatas.DataSet)do
begin
Close;
if Input[1]<>'' then
CommandText := Input[1] ;
Open;
end;
Result := TSQLDataSet(DSP_GetDatas.DataSet).RecordCount;
end else
begin
TSQLDataSet(DataSet).First;
TSQLDataSet(DataSet).MoveBy(Input[0]-1);
Result := GetRecords(Input[1],RecsOut,MetaDataOption);
end;
end;
end;
end;

function TGMService.DSP_MultiGetDataRequest(Sender: TObject;
Input: OleVariant): OleVariant;
var
RecsOut:Integer;
begin
if VarIsArray(Input) then
begin
with Sender as TDataSetProviderdo
begin
if Input[0]=0 then
begin
with TSQLDataSet(DataSet)do
begin
Close;
if Input[1]<>'' then
CommandText := Input[1] ;
Open;
end;
Result := TSQLDataSet(DataSet).RecordCount;
end
else
begin
TSQLDataSet(DataSet).First;
TSQLDataSet(DataSet).MoveBy(Input[0]-1);
Result := GetRecords(Input[1],RecsOut,MetaDataOption);
end;
end;
end;
end;

procedure TGMService.MultiCDSGet(aGetType: Shortint;
const aProviderName: WideString;
abegin
, aGetCount: OleVariant;
out vDatas, oError: OleVariant);
var
RecsOut:Integer;
begin
if (aProviderName = '') or (FindComponent(aProviderName)=nil) then
//找不到provider(包括Multiget)
begin
oError:='Provider not found!';
exit;
end;

with TDataSetProvider(FindComponent(aProviderName))do
begin
if not Assigned(DataSet) then
begin
oError := ' Provider has not been assigned an available dataset!';
exit;
end;
if aGetType=0 then
//客户端Dofirst,取RecordCount
begin
with TSQLDataSet(DataSet)do
begin
if not Active then
Open;
vDatas := RecordCount;
end;
end else
//分批量取数据
begin
if not DataSet.Active then
DataSet.Open;
TSQLDataSet(DataSet).First;
TSQLDataSet(DataSet).MoveBy(abegin
-1);
vDatas := GetRecords(aGetCount,RecsOut,MetaDataOption);
end;
end;
end;

initialization
TComponentFactory.Create(ComServer, TGMService,
Class_GMService, ciMultiInstance, tmApartment);
end.
 
{************************************************************************}
{ }
{ GMPackage. MultiTrdCDSGet.pas 2003-11-28 }
{ }
{ Designer (C) 2002, 2003 James.Wonken }
{ }
{************************************************************************}
{Public Functions: }
{ }
{ 多线程取ClientDataset单元。要求Cds指定了数据提供者Provider. }
{ TMultiTrdCDSGet.Create(5,5000,CDS1);
}
{ 开5个线程,每线程取5000条数据 }
{************************************************************************}
unit MultiTrdCDSGet;
interface
uses
Classes,Messages, DBClient,ComObj,ActiveX,GMServer_TLB, DB,Windows, SysUtils,
SyncObjs, Provider, Midas;
const
SubFinishedMsg = WM_USER + 128;
type
TMultiTrdCDSGet = class(TThread)
private
FTotalThread:Integer;
FThreadCount:Integer;
FPrepareThread:Integer;
FPacketRec:Integer;
FCDS:TClientDataSet;
FProvName:String;
FRecCount:Integer;
protected
proceduredo
First;
proceduredo
Calculate;
proceduredo
AddSub;
procedure Execute;
override;
procedure CreateNewGet(abegin
,aGetCount:Integer);
public
constructor Create(aThreadCount,aPacketRecCount:Integer;aCDS:TClientDataSet);
Destructor Destroy;override;
end;

implementation
uses Variants, TrdCDSGetPacket;
{ TMultiTrdCDSGet }
constructor TMultiTrdCDSGet.Create(aThreadCount,aPacketRecCount: Integer;
aCDS: TClientDataSet);
begin
inherited Create(True);
FreeOnTerminate := True;
FThreadCount := aThreadCount;
FPacketRec := aPacketRecCount ;
FCDS := aCDS ;
FProvName := FCDS.ProviderName;
if FProvName='' then
Terminate;
OleCheck(CoInitialize(nil));
Resume;
end;

procedure TMultiTrdCDSGet.CreateNewGet(abegin
,aGetCount:Integer);
begin
TTrdCDSGetPacket.Create(Self.ThreadID,abegin
,aGetCount,FCDS);
end;

destructor TMultiTrdCDSGet.Destroy;
begin
CoUninitialize;
inherited Destroy;
end;

procedure TMultiTrdCDSGet.DoAddSub;
var
ThreadL:TCriticalSection;
begin
if FPrepareThread< FThreadCount then
FPrepareThread := FThreadCount ;
if FPrepareThread > FTotalThread then
begin
Terminate;
end
else
begin
ThreadL := TCriticalSection.Create;
ThreadL.Acquire;
try
FPrepareThread:=FPrepareThread+1;
finally
ThreadL.Release;
end;
CreateNewGet((FPrepareThread-1)*FPacketRec+1,FPacketRec);;
end;
end;

procedure TMultiTrdCDSGet.DoCalculate;
var
IOut:Integer;
begin
if (FRecCount mod FPacketRec) >0 then
IOut := 1 else
IOut := 0;
FTotalThread := (FRecCount div FPacketRec) + IOut ;
if FTotalThread<=FThreadCount then
FThreadCount := FTotalThread ;
end;

procedure TMultiTrdCDSGet.DoFirst;
var
MyServ:IGMService;
vDatas,aError:OleVariant;
begin
MyServ:=CreateCOMObject(CLASS_GMService) as IGMService;
MyServ.MultiCDSGet(0,FCDS.ProviderName,0,0,vDatas,aError);
FRecCount := vDatas;
end;

procedure TMultiTrdCDSGet.Execute;
var
i:Integer;
Msg : TMsg;
begin
FreeOnTerminate := True;
do
First;
do
Calculate ;
for i:= 1 to FThreadCountdo
begin
CreateNewGet((i-1)*FPacketRec+1,FPacketRec);
end;
while (not Terminated)do
begin
if PeekMessage(Msg,0,0,0,PM_REMOVE) then
begin
if (Msg.message = SubFinishedMsg) then
begin
do
AddSub;
end;
end;
end;
end;

end.
 
{************************************************************************}
{ }
{ Project1 . TrdCDSGetPacket.pas 2003-12-4 }
{ }
{ Designer (C) 2002, 2003 James.Wonken }
{ }
{************************************************************************}
{Public Functions: }
{ TMultiTrdCDSGet的子线程,不能公布使用。 }
{ }
{ }
{ }
{************************************************************************}

unit TrdCDSGetPacket;
interface
uses
Classes,Messages, SysUtils,ComObj,ActiveX,GMServer_TLB, DB, DBClient, Windows, Provider;
type
TTrdCDSGetPacket = class(TThread)
private
FThreadID:Cardinal;
FCDS:TClientDataSet;
Fbegin
,FGetCount:Integer;
protected
procedure Execute;
override;
proceduredo
Finished(Sender:TObject);
proceduredo
Get;
public
constructor Create(aThread:Cardinal;abegin
,aGetCount:Integer;aCDS:TClientDataSet);
end;

implementation
uses Variants, MultiTrdCDSGet;
{ TTrdCDSGetPacket }
constructor TTrdCDSGetPacket.Create(aThread:Cardinal;abegin
,aGetCount:Integer;aCDS:TClientDataSet);
begin
FreeOnTerminate := True;
OnTerminate :=do
Finished;
FThreadID := aThread ;
FCDS := aCDS;
Fbegin
:= abegin
;
FGetCount := aGetCount;
inherited Create(False);
end;

procedure TTrdCDSGetPacket.DoFinished(Sender:TObject);
begin
PostThreadMessage(FThreadID,SubFinishedMsg,0,0);
end;

procedure TTrdCDSGetPacket.DoGet;
var
MyServ:IGMService;
vDatas,aError:OleVariant;
begin
OleCheck(CoInitialize(nil));
try
MyServ:=CreateCOMObject(CLASS_GMService) as IGMService;
MyServ.MultiCDSGet(1,FCDS.ProviderName,Fbegin
,FGetCount,vDatas,aError);
FCDS.AppendData(vDatas,False);
finally
CoUninitialize;
end;
end;

procedure TTrdCDSGetPacket.Execute;
begin
FreeOnTerminate := True;
Synchronize(DoGet);
end;

end.
 
{************************************************************************}
{ }
{ GMPackage. TMultiTrdCmdGet.pas 2003-11-28 }
{ }
{ Designer (C) 2002, 2003 James.Wonken }
{ }
{************************************************************************}
{Public Functions: }
{ 要求提供SQL语句,并指定CDS的PROVIDER为服务器端的特定Provider, }
{ 该Provider应该提供了OnDataRequest方法。 }
{ TMultiTrdCmdGet.Create('select * from B_Unit',5,5000,CDS_2);
}
{ 创建5个子线程每线程取得5000条数据 。 }
{ }
{************************************************************************}
unit MultiTrdCmdGet;
interface
uses
Classes,Messages, DBClient,ComObj,ActiveX,GMServer_TLB, DB,Windows, SysUtils,
SyncObjs, Provider, Midas;
const
CmdSubFinishedMsg = WM_USER + 129;
type
TMultiTrdCmdGet = class(TThread)
private
FTotalThread:Integer;
FThreadCount:Integer;
FPrepareThread:Integer;
FPacketRec:Integer;
FSQLStr:String;
FCDS:TClientDataSet;
FRecCount:Integer;
protected
proceduredo
First;
proceduredo
Calculate;
proceduredo
AddSub;
procedure Execute;
override;
procedure CreateNewGet(abegin
,aGetCount:Integer);
public
constructor Create(aSqlStr:String;aThreadCount,aPacketRecCount:Integer;aCDS:TClientDataSet);
Destructor Destroy;override;
end;

implementation
uses TrdCmdGetPacket, Variants;
{ TMultiTrdCmdGet }
constructor TMultiTrdCmdGet.Create(aSqlStr:String;aThreadCount,aPacketRecCount: Integer;
aCDS: TClientDataSet);
begin
OleCheck(CoInitialize(nil));
inherited Create(True);
FreeOnTerminate := True;
FSQLStr := aSqlStr ;
FThreadCount := aThreadCount;
FPacketRec := aPacketRecCount ;
FCDS := aCDS ;
FRecCount := 0;
Resume;
end;

procedure TMultiTrdCmdGet.CreateNewGet(abegin
,aGetCount:Integer);
begin
TTrdCmdGetPacket.Create(Self.ThreadID,abegin
,aGetCount,FCDS);
end;

destructor TMultiTrdCmdGet.Destroy;
begin
CoUninitialize;
inherited Destroy;
end;

procedure TMultiTrdCmdGet.DoAddSub;
var
ThreadL:TCriticalSection;
begin
if FPrepareThread< FThreadCount then
FPrepareThread := FThreadCount ;
if FPrepareThread > FTotalThread then
begin
Terminate;
end
else
begin
ThreadL := TCriticalSection.Create;
ThreadL.Acquire;
try
FPrepareThread:=FPrepareThread+1;
finally
ThreadL.Release;
end;
CreateNewGet((FPrepareThread-1)*FPacketRec+1,FPacketRec);;
end;
end;

procedure TMultiTrdCmdGet.DoCalculate;
var
IOut:Integer;
begin
if (FRecCount mod FPacketRec) >0 then
IOut := 1 else
IOut := 0;
FTotalThread := (FRecCount div FPacketRec) + IOut ;
if FTotalThread<=FThreadCount then
FThreadCount := FTotalThread ;
end;

procedure TMultiTrdCmdGet.DoFirst;
var
GetInput:OleVariant;
begin
GetInput:=VarArrayCreate([0,1],varVariant);
GetInput[0]:=0;
GetInput[1]:=FSQLStr;
FRecCount := FCDS.DataRequest(GetInput);
end;

procedure TMultiTrdCmdGet.Execute;
var
i:Integer;
Msg : TMsg;
begin
FreeOnTerminate := True;
Synchronize(DoFirst);
do
Calculate ;
for i:= 1 to FThreadCountdo
begin
CreateNewGet((i-1)*FPacketRec+1,FPacketRec);
end;
while (not Terminated)do
begin
if PeekMessage(Msg,0,0,0,PM_REMOVE) then
begin
if (Msg.message = CmdSubFinishedMsg) then
begin
do
AddSub;
end;
end;
end;
end;

end.
 
{************************************************************************}
{ }
{ Project1 . TrdCmdGetPacket.pas 2003-12-4     }
{ }
{ Designer (C) 2002, 2003 James.Wonken }
{ }
{************************************************************************}
{Public Functions: }
{ TMultiTrdCmdGet子线程,不能公布使用。 }
{ }
{ }
{ }
{************************************************************************}

unit TrdCmdGetPacket;
interface
uses
Classes,Messages, SysUtils,ComObj,ActiveX,GMServer_TLB, DB, DBClient, Windows, Provider;
type
TTrdCmdGetPacket = class(TThread)
private
FThreadID:Cardinal;
FCDS:TClientDataSet;
Fbegin
,FGetCount:Integer;
protected
procedure Execute;
override;
proceduredo
Finished(Sender:TObject);
proceduredo
Get;
public
constructor Create(aThread:Cardinal;abegin
,aGetCount:Integer;aCDS:TClientDataSet);
end;

implementation
uses MultiTrdCmdGet, Variants;
{ TTrdCmdGetPacket }
constructor TTrdCmdGetPacket.Create(aThread:Cardinal;abegin
,aGetCount:Integer;aCDS:TClientDataSet);
begin
FreeOnTerminate := True;
OnTerminate :=do
Finished;
FThreadID := aThread ;
FCDS := aCDS;
Fbegin
:= abegin
;
FGetCount := aGetCount;
inherited Create(False);
end;

procedure TTrdCmdGetPacket.DoFinished(Sender:TObject);
begin
PostThreadMessage(FThreadID,CmdSubFinishedMsg,0,0);
end;

procedure TTrdCmdGetPacket.DoGet;
var
GetPost:OleVariant;
begin
GetPost:=VarArrayCreate([0,1],varVariant);
GetPost[0]:= Fbegin
;
GetPost[1]:= FGetCount;
FCDS.AppendData(FCDS.DataRequest(GetPost),False);
end;

procedure TTrdCmdGetPacket.Execute;
begin
FreeOnTerminate := True;
Synchronize(DoGet);
end;

end.
 
测试过了。5个线程,每线程6000条,取3万条数据要2-5秒
 
wonken:
能把完整的例子发个给我吗?多谢:
hotject@hotmail.com
 
如果能,我也要,共同进步,谢谢楼主
hailer@tom.com
 
这不用例子了,加入这几个单元文件,Uses一下,然后随便加一个CDS在窗体,就可以通过create过程来取得服务器端DSP的数据了,注意各单元用途,几个多线程只适用大量数据,如果数据少,设定得不好的话,或许比单线程还要慢。
 
后退
顶部