{--------------------------------------------------------------}
{算法介绍:}
{题库系统按5000一组分组比较,5000道题内开启10个线程,分别从 }
{0,500,1000,1500,2000,2500,3000,3500,4000,4500位置开始与其后的所有试题比较}
{比较完成返回比较结果;等待所有5000已完成,然后循环5000的下一组,}
{比较完成返回第2组5000的比较结果 }
{ }
{--------------------------------------------------------------}
unit StrDiffThread;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
const
C_threadCnt = 10; //开启线程个数
C_groupCnt = 5000; //题数最小分组
C_RetMaxCnt = 1000; //列表最多返回1000*10个值
C_SPLITER = '-';
type
TMyThread = class(TThread)
protected
procedure Execute; override;
public
iThreadId: Integer;
bIsInUse: Boolean; //是否已启用
bFinished: Boolean; //线程是否结束
iTotalCount: integer; //试题总数
iTotalItemList: TStringList; //试题字符串
iRetList: TStringList; //返回比较结果字符串
iCurrIndex: integer; //正在处理第几题;
iCurrPercent:integer ;//当前处理试题的比例;
iStart: integer; //起始位置
iMaxValue: Double; // 0..1 之间的小数
iGainCount: Integer; //本线程分配的试题个数(尾线程,题数不足5000)
end;
function InitArrayFromItemBank(var itemList: TStringList; maxValue: Double): Boolean;
function GetAllThreadFinished(): Boolean;
function GetThreadPercent(index:Integer):integer;
function GetThreadRetList(index:Integer):TStringList;
var
RunThread: array[0..C_threadCnt] of TMyThread; //运行线程实例对象
{----------------------implementation---------------------- ------}
implementation
uses CnStrDiff;
function InitArrayFromItemBank(var itemList: TStringList; maxValue: Double): Boolean;
var
i, perCnt: integer;
begin
Result := false;
if (itemList = nil) or (itemList.Count = 0) then Exit;
//组内试题个数;
if itemList.Count < C_groupCnt then
perCnt := Round(itemList.Count / C_threadCnt) //10个线程中每个线程分配的比对题个数5000/10=500
else
perCnt := Round(C_groupCnt / C_threadCnt);
for i := 0 to C_threadCnt - 1 do
begin
if RunThread[i] <> nil then
begin
if not TMyThread(RunThread[i]).Terminated then
TMyThread(RunThread[i]).Terminate; //需等待线程结束
if TMyThread(RunThread[i]).iRetList <> nil then
TMyThread(RunThread[i]).iRetList.Free; //释放临时变量
TMyThread(RunThread[i]).Free;
TMyThread(RunThread[i]) := nil;
end;
RunThread[i] := TMyThread.Create(true);
RunThread[i].iThreadId := i;
RunThread[i].bIsInUse := true;
RunThread[i].iTotalItemList := itemList;
RunThread[i].iTotalCount := itemList.Count; //题库总题量
RunThread[i].iGainCount := perCnt; //分配题个数
RunThread[i].iStart := i * perCnt; //从哪个题开始比对
RunThread[i].iCurrIndex := i * perCnt; //正在比对第0题
RunThread[i].iCurrPercent := 0;
RunThread[i].bFinished := false;
RunThread[i].iMaxValue := maxValue;
RunThread[i].iRetList := TstringList.Create; //返回结果
RunThread[i].Resume;
Application.ProcessMessages;
end;
Result := true;
end;
function GetThreadPercent(index:Integer):integer;
begin
Result := 0 ;
if ( index >= 0) and ( index < C_threadCnt) and (RunThread[index] <> nil ) then
Result := RunThread[index].iCurrPercent;
end;
function GetThreadRetList(index:Integer):TStringList;
begin
Result := nil ;
if ( index >= 0) and ( index < C_threadCnt) and (RunThread[index] <> nil ) then
Result := RunThread[index].iRetList;
end;
procedure TMyThread.Execute;
var
i, j: Integer;
ret: Double;
sourceStr, destStr, resStr, sourceId, destId: string;
begin
FreeOnTerminate := false; {这可以让线程执行完毕后随即不释放}
bFinished := false;
iCurrPercent := 0 ;
for i := iStart to iStart + iGainCount - 1 do
begin
sourceStr := iTotalItemList.Strings[i];
//当前处理问题进度
iCurrPercent := Round( 100*i/(iStart+iGainCount));
//0-500与其后 1-5000比较
for j := i + 1 to iTotalCount - 1 do
begin
destStr := iTotalItemList.strings[j];
//比对字符串
ret := SimilarText(sourceStr, destStr, True);
//返回值列表不超限且比对结果超过设置比例
if (iRetList <> nil) and (iRetList.Count < C_RetMaxCnt) and (ret >= iMaxValue) then
begin
resStr := FormatFloat('00.00%', ret * 100);
sourceId := Copy(sourceStr, 0, Pos(C_SPLITER, sourceStr) - 1);
destId := Copy(destStr, 0, Pos(C_SPLITER, destStr) - 1);
iRetList.Add(sourceId + C_SPLITER + destId + C_SPLITER + resStr);
end;
end;
end;
iCurrPercent := 100;
bFinished := true;
end;
function GetAllThreadFinished(): Boolean;
var
i: integer;
begin
Result := true;
for i := 0 to C_threadCnt - 1 do
if not RunThread[i].bFinished then
begin
Result := false;
Break;
end;
end;
end.
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, RzPrgres, StdCtrls, Buttons, ComCtrls;
type
TForm2 = class(TForm)
BitBtn1: TBitBtn;
RzProgressBar1: TRzProgressBar;
Label1: TLabel;
Label2: TLabel;
RzProgressBar2: TRzProgressBar;
Label3: TLabel;
RzProgressBar3: TRzProgressBar;
Label4: TLabel;
RzProgressBar4: TRzProgressBar;
Label5: TLabel;
RzProgressBar5: TRzProgressBar;
RzProgressBar6: TRzProgressBar;
Label6: TLabel;
Label7: TLabel;
RzProgressBar7: TRzProgressBar;
Label8: TLabel;
RzProgressBar8: TRzProgressBar;
Label9: TLabel;
RzProgressBar9: TRzProgressBar;
Label10: TLabel;
RzProgressBar10: TRzProgressBar;
Label11: TLabel;
Edit1: TEdit;
lv_result: TListView;
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
function GetItemDBList(index: integer; var dbList: TStringList): Boolean;
public
{ Public declarations }
itemgroupList: TStringList;
end;
var
Form2: TForm2;
implementation
uses StrDiffThread;
{$R *.dfm}
function TForm2.GetItemDBList(index: integer; var dbList: TStringList): Boolean;
var
i: Integer;
begin
Result := false;
//获取第index组试题,每组获取C_groupCnt个试题;
for i := 0 to C_groupCnt - 1 do
begin
if dbList <> nil then
dbList.Add(IntToStr(i + index * C_groupCnt) + '-' + FormatdateTime('yyyy-mm-dd HH:MM:SS', Now));
end;
end;
procedure TForm2.BitBtn1Click(Sender: TObject);
var
i, k, l, iGroupCnt, totalcnt: Integer;
similar: Double;
itemretList: TStringList;
listitem: TListItem;
begin
totalCnt := 6000; //总题数
similar := StrToFloat(Edit1.text);
//题库按一组groupCnt个题分若干组
if totalCnt mod C_groupCnt = 0 then
iGroupCnt := totalCnt div C_groupCnt
else
iGroupCnt := totalCnt div C_groupCnt + 1;
//按组循环
for i := 0 to iGroupCnt - 1 do
begin
if itemgroupList <> nil then
itemgroupList.Free;
itemgroupList := TStringList.Create;
//读取试题存入itemgroupList
GetItemDBList(i, itemgroupList);
if InitArrayFromItemBank(itemgroupList, similar) then
begin
//等待所有线程结束
while not GetAllThreadFinished() do
begin
for k := 0 to C_threadCnt - 1 do
begin
TRzProgressBar(self.FindComponent('RzProgressBar' + inttostr(k + 1))).Percent := GetThreadPercent(k);
end;
Application.ProcessMessages;
Sleep(3000);
end;
for k := 0 to C_threadCnt - 1 do
begin
itemretList := GetThreadRetList(k);
if (itemretList <> nil) and (itemretList.count > 0) then
begin
for l := 0 to itemretList.count - 1 do
begin
listitem := lv_result.Items.Add;
listitem.Caption := IntToStr(l);
listitem.SubItems.Add(inttostr(k + 1));
listitem.SubItems.Add(itemretList.strings[l]);
end;
end;
end;
end;
ShowMessage('处理完第'+inttostr(i)+'组');
end;
end;
end.