【控件功能】我来做练习-第58课-HTTPPool、PrimePool、ThreadPool,线程池

本文详细介绍了Delphi编程中如何使用HTTPPool、PrimePool和ThreadPool实现线程池管理。通过示例代码展示了如何创建任务、设置并发数、监控任务状态以及取消任务等操作,帮助开发者更有效地管理和调度线程资源。
摘要由CSDN通过智能技术生成

HTTPPool、PrimePool、ThreadPool,线程池

提示:这里可以添加技术概要
请添加图片描述

核心源码

提示:这里可以添加技术整体架构
procedure DemandInitProc(Manager:TPoolManager);
begin
if not Assigned(MainForm) then
Exit;

Manager.ConcurrentWorkersCount:=Trunc(MainForm.ConcurrentWorkersEdit.Value);
Manager.SpareWorkersCount:=Trunc(MainForm.SpareWorkersEdit.Value);

if not Manager.RestoreOwners then
	Manager.RegisterOwner(MainForm, MainForm.TasksStatus, MainForm.TasksComplete);

end;

{** TMainForm **}

procedure TMainForm.AddTasksButtonClick(Sender:TObject);
var
cc:Integer;
HTTPTask:THTTPTask;
begin
LogMemo.Clear;
{**
* Create once, assign needed event handlers and make later only clones with some customizing’s
*}
HTTPTask:=THTTPTask.Create(Self);
HTTPTask.OnDone:=TaskDone;
HTTPTask.OnStart:=TaskStart;
HTTPTask.OnCancel:=TaskCanceled;
HTTPTask.OnDownloadStatus:=TaskDownloadStatus;

for cc:=0 to URLMemo.Lines.Count - 1 do
begin
	HTTPTask.URL:=URLMemo.Lines[cc];

	if cc >= (URLMemo.Lines.Count - 3) then
		HTTPTask.Priority:=tpHighest
	else
		HTTPTask.Priority:=tpLowest;

	HTTPManager.AddTask(HTTPTask);

	HTTPTask:=THTTPTask(HTTPTask.Clone);
end;

end;

procedure TMainForm.CancelTasksButtonClick(Sender:TObject);
begin
if THTTPManager.HasSingleton then
HTTPManager.CancelTasksByOwner(Self);
end;

procedure TMainForm.ConcurrentWorkersEditChange(Sender:TObject);
begin
if THTTPManager.HasSingleton then
HTTPManager.ConcurrentWorkersCount:=Trunc(ConcurrentWorkersEdit.Value);
end;

procedure TMainForm.FormCreate(Sender:TObject);
begin
THTTPManager.RegisterSingletonOnDemandProc(DemandInitProc);
end;

procedure TMainForm.FormDestroy(Sender:TObject);
begin
TPoolManager.TerminateSingletonInstances;
end;

procedure TMainForm.SpareWorkersEditChange(Sender:TObject);
begin
if THTTPManager.HasSingleton then
HTTPManager.SpareWorkersCount:=Trunc(SpareWorkersEdit.Value);
end;

procedure TMainForm.TaskCanceled(Sender:TObject);
var
HTTPTask:THTTPTask;
begin
if not (Assigned(Sender) and (Sender is THTTPTask)) then
Exit;
HTTPTask:=THTTPTask(Sender);

LogMemo.Lines.Add(Format('Task canceled for "%s"', [HTTPTask.URL]));

end;

procedure TMainForm.TaskDone(Sender:TObject);
var
HTTPTask:THTTPTask;
ThreadID:Cardinal;
begin
if not (Assigned(Sender) and (Sender is THTTPTask)) then
Exit;
HTTPTask:=THTTPTask(Sender);

if Assigned(HTTPTask.Owner) and (HTTPTask.Owner is TPoolWorker) then
	ThreadID:=TPoolWorker(HTTPTask.Owner).ThreadID
else
	ThreadID:=0;

LogMemo.Lines.Add(Format('Task done for "%s". [HTTP-Code: %d], [Response-Size: %d Bytes], [ThreadID: %d]',
	[HTTPTask.URL, HTTPTask.ResponseCode, HTTPTask.ResponseSize, ThreadID]));

end;

procedure TMainForm.TaskDownloadStatus(Sender:TObject; Progress, MaxProgress:Int64);
var
HTTPTask:THTTPTask;
begin
if not (Assigned(Sender) and (Sender is THTTPTask)) then
Exit;
HTTPTask:=THTTPTask(Sender);
LogMemo.Lines.Add(Format(‘%d %% (%d of %d Bytes) downloaded of “%s”’,
[Round(Progress / MaxProgress * 100), Progress, MaxProgress, HTTPTask.URL]));
end;

procedure TMainForm.TasksComplete(Sender:TObject);
begin

end;

procedure TMainForm.TasksStatus(Sender:TObject; Progress:Single);
begin
ProgressBar.Position:=Round(Progress * 100);
end;

unit ThreadPool;

interface

{$INCLUDE Compile.inc}

uses
SysUtils, Generics.Defaults, Generics.Collections, Contnrs, SyncObjs, Windows, Classes, Forms
{ KaTeX parse error: Expected 'EOF', got '}' at position 16: IFDEF CODE_SITE}̲ , CodeSiteLog…ENDIF};

const
Version = ‘1.0.6’;

type
{**
* Class forward declarations
}
TPoolTask = class;
TPoolWorker = class;
TPoolManager = class;
{
*
* Class type declarations
}
TPoolTaskClass = class of TPoolTask;
TPoolWorkerClass = class of TPoolWorker;
TPoolManagerClass = class of TPoolManager;
{
*
* Derived generic list types
}
TWorkerList = TObjectList;
TTaskList = TObjectList;
{
*
* Enumeration of pissible states of a task
*
* @see TPoolTask
}
TTaskState = (tsUnknown, tsInWork, tsError, tsSuccess);
{
*
* Enumeration for common priorities of a task
*
* @see TPoolTask.Priority
}
TTaskPriority = (
tpLowest = 0, tpLower = 1, tpLow = 2,
tpNormal = 3,
tpHigh = 4, tpHigher = 5, tpHighest = 255,
tpCustom = -1);
{
*
* Enumeration of possible states of a worker
*
* @see TPoolWorker
}
TWorkerState = (wsReady, wsBusy, wsTaskDone);
{
*
* Anonymous method for a task
*
* Compatible to TPoolTask.IsTheSame
}
TTaskFunc = reference to function(Task:TPoolTask):Boolean;
{
*
* Status event
*
* @param Progress Float value between 0 and 1. 1 = 100% = Complete.
*}
TStatusEvent = reference to procedure(Sender:TObject; Progress:Single);

TManagerProc = TProc<TPoolManager>;
{**
 * Anonymous notify event, which is compatible with commonly used TNotifyEvent
 *}
TAnonymousNotifyEvent = reference to procedure(Sender:TObject);

{**
 * TPoolTask represent a dual data holder
 *
 * Derived task classes can add further input fields and also any output fields.
 * But what are input and what are output fields?
 * This is answered by your implementation of the correspondig TPoolWorker.
 *}
TPoolTask = class(TObject)
private
	{**
	 * As long as the task is processed, the reference of the worker stays here
	 *
	 * This info is set and required only by the manager, don't access it from workers at all.
	 *}
	FProcessingBy:TPoolWorker;

	function GetPriority:TTaskPriority;
	procedure SetPriority(Priority:TTaskPriority);
protected
	FOwner:TObject;
	FOnStart:TAnonymousNotifyEvent;
	FOnCancel:TAnonymousNotifyEvent;
	FOnDone:TAnonymousNotifyEvent;
	FState:TTaskState;
	FPriority:Byte;

	class function Compare(const Left, Right:TPoolTask):Integer; virtual;

	procedure Assign(Source:TPoolTask); virtual;
	function IsTheSame(Compare:TPoolTask):Boolean; virtual;

	{**
	 * Both, Priority and PriorityRaw, sets the same field for the priority of the task
	 *
	 * The higher the priority the sooner it's taked for processing, if not all tasks
	 * can be processed at the same time.
	 *
	 * PriorityRaw is introduced for purposes, where you need a finer resolution (range of byte)
	 * Priority is comfortable, but allows only 7 common priorities through a enumeration
	 *
	 * Publish one of them in your derived task, if you need it.
	 *
	 * You must also enable the property SortTasks (disabled by default) in the corresponding
	 * derived manager.
	 *
	 * @see TPoolManager.SortTasks
	 *}
	property Priority:TTaskPriority read GetPriority write SetPriority;
	property PriorityRaw:Byte read FPriority write FPriority;
public
	constructor Create(Owner:TObject); virtual;

	function Clone:TPoolTask;

	property Owner:TObject read FOwner;
	property State:TTaskState read FState;
	{**
	 * Generic event, which is fired, if the processing of the task is started
	 *}
	property OnStart:TAnonymousNotifyEvent read FOnStart write FOnStart;
	{**
	 * Generic event, which is fired, if the task is canceled
	 *}
	property OnCancel:TAnonymousNotifyEvent read FOnCancel write FOnCancel;
	{**
	 * Generic event, which is fired, if the task is done and was not canceled
	 *}
	property OnDone:TAnonymousNotifyEvent read FOnDone write FOnDone;
end;

TThreadProcedures = class;

{**
 * TPoolThread contains only the intersected structures/functionality of TPoolWorker and
 * TPoolManager and act as the base class for them.
 *
 * The Execute method is full implemented and should be not overriden by descendants, instead
 * a simple "Execution Loop" concept is introduced there:
 * - InitializeExecutionLoop is executed once before the loop
 * - ExecutionLoop is so long executed in loop as ExecutionLoopCondition returns TRUE.
 *   But each run of the loop requires a signal on MainSignal (see method TriggerMainSignal).
 * - If ExecutionLoopCondition returns FALSE, the loop will be breaked and FinalizeExecutionLoop
 *   is called finally.
 *
 * Don't create any instances of this class!
 *}
TPoolThread = class(TThread)
private
	FMainSignal:TEvent;
	FInExecutionLoop:Boolean;

	function GetSleeping:Boolean;
protected
	procedure ExecutionLoopInitialize; virtual; abstract;
	function ExecutionLoopCondition:Boolean; virtual;
	procedure ExecutionLoop; virtual; abstract;
	procedure ExecutionLoopFinalize; virtual; abstract;

	procedure Execute; override;

	procedure TriggerMainSignal;

	property MainSignal:TEvent read FMainSignal;
	{**
	 * Says, whether this thread is currently in active execution. It's FALSE, if it waits for
	 * the signal (MainSignal)
	 *}
	property InExecutionLoop:Boolean read FInExecutionLoop;
public
	constructor Create(CreateSuspended:Boolean);
	destructor Destroy; override;

	procedure Terminate; reintroduce; virtual;

	{**
	 * Says, whether this thread is currently sleeping.
	 * It's TRUE, if it waits for the signal (MainSignal).
	 *}
	property Sleeping:Boolean read GetSleeping;
end;

{**
 * TPoolWorker is our workhorse and should do the work to complete a task
 *
 * This implementation contains all needed mechanisms for interacting with the corresponding
 * TPoolManager.
 *
 * Of course, here are no code for doing the whole work. This must be implemented in
 * ExecuteTask by the derived class.
 *}
TPoolWorker = class(TPoolThread)
private

{ KaTeX parse error: Expected 'EOF', got '}' at position 16: IFDEF CODE_SITE}̲ FWorkerIndex…ENDIF}
FOwner:TPoolManager;
FState:TWorkerState;
FCanceled:Boolean;
FProcessTasks:TTaskList;

{ KaTeX parse error: Expected 'EOF', got '}' at position 16: IFDEF CODE_SITE}̲ property Wor…ENDIF}
property ProcessTasks:TTaskList read FProcessTasks;
protected
FContextTask:TPoolTask;

	procedure FireEvent(FireEventProc:TProc<TPoolTask>; HasEventFunc:TTaskFunc);

	procedure InitializeTask(SameTasks:TTaskList);
	{**
	 * ExecuteTask is the right place to implement the main work
	 *
	 * You have to use the property ContextTask for do the job.
	 *
	 * It's important to call the DoneTask method with a corresponding value in any case,
	 * if the task is done.
	 *
	 * As running condition they should check for the property Canceled, not for Terminated.
	 *
	 * For example:
	 * - On error: DoneTask(FALSE);
	 * - On success: DoneTask(TRUE);
	 *}
	procedure ExecuteTask; virtual; abstract;
	procedure DoneTask(Successful:Boolean);

	procedure ExecutionLoopInitialize; override;
	procedure ExecutionLoop; override;
	procedure ExecutionLoopFinalize; override;

	procedure Cancel;

	property Owner:TPoolManager read FOwner;
	property Canceled:Boolean read FCanceled;
	property ContextTask:TPoolTask read FContextTask;
public
	constructor Create(Owner:TPoolManager); virtual;
	destructor Destroy; override;

	procedure Terminate; override;

	property State:TWorkerState read FState write FState;
end;

{**
 * TPoolManager is the key class of the whole concept. It's almost full implemented.
 * Derived managers must only implement the class method WorkerClass.
 * For more comfort it's recommended to reintroduce the class method Singleton.
 * Nothing more is needed, but you can introduce new methods for easier tasks handling.
 *
 * @see TPoolManager.WorkerClass
 * @see TPoolManager.Singleton
 *
 * Singleton pattern
 * -----------------
 *
 * Because it makes no sense, to hold any instances of the manager, the singleton pattern was
 * choosed for rich features (e.g. Demand mode).
 *
 * To access the manager you should call always the class method Singleton on the derived
 * manager class, which always return a valid instance of the corresponding class.
 * On the first call it creates and starts the manager thread and you are instantly able,
 * to add your tasks.
 *
 * Of course you are able to instantiate many instances manually, but this is not a part of
 * concept and the behaviour isn't tested.
 *
 * @see TPoolManager.Singleton
 *
 * Concurrent workers
 * ------------------
 *
 * Each manager is able to manage a amount of workers (TPoolWorker) for processing the added
 * tasks. The workers are created only on demand. Each worker get's the next task from the
 * task queue, after it has done their current one. If there are no further tasks in the queue,
 * all sleeping workers are terminated automatically. But this behaviour is influenced by the
 * property SpareWorkersCount.
 *
 * @see TPoolManager.ConcurrentWorkersCount
 *
 * Spared workers
 * --------------
 *
 * You can define a amount of workers, which are not terminated automatically, unless you
 * decrease the property SpareWorkersCount or terminate the manager manually. This is usefull
 * for often small tasks.
 *
 * The "Demand mode" is disabled, if you define more than 0 SpareWorkersCount.
 *
 * @see TPoolManager.SpareWorkersCount
 *
 * Demand mode
 * -----------
 *
 * By default a single instance/thread for each derived TPoolManager class is created by the
 * first call of the class method Singleton and resist, until your application is closed or
 * you manually terminate it.
 *
 * This bahavior can be changed, by simple passing an "init" procedure, before the first call
 * of Singleton is done. If you do that, the manager terminates himself automatically, if all
 * added tasks are done or get canceled. The property SpareWorkersCount must be zero (0),
 * otherwise the demand mode can't be activated.
 *
 * @see TPoolManager.RegisterSingletonOnDemandProc
 *}
TPoolManager = class(TPoolThread)
private
	{**
	 * I dont't like to waste the global namespace with types, which are only locally required
	 *}
	type
	TTaskComparer = TDelegatedComparer<TPoolTask>;

	TOwner = class
	public
		Owner:TObject;
		TasksTotalCount:Integer;
		TasksDoneCount:Integer;
		OnTasksStatus:TStatusEvent;
		OnTasksComplete:TAnonymousNotifyEvent;
	end;

	TOwnerList = TObjectList<TOwner>;

	TOwnersAssign = class
		ManagerClass:TPoolManagerClass;
		Owners:TOwnerList;
	end;

	TDemandProcAssign = class
		ManagerClass:TPoolManagerClass;
		DemandProc:TManagerProc;
	end;
{**
 * Private section for class related stuff
 *}
private
	class var
	FSingleInstances:array of TPoolManager;
	FDemandProcs:array of TDemandProcAssign;
	FStoredOwners:array of TOwnersAssign;

{ KaTeX parse error: Expected 'EOF', got '}' at position 22: … COMPILER_15_UP}̲ FCPUCount:Ca…ENDIF}

	class function GetDemandProcIndex(ReturnOnFreeIndex:Boolean = FALSE):Integer;
	class function GetCPUCount:Integer;
{**
 * Private section for object related stuff
 *}
private
	FOwners:TOwnerList;
	FOwnersDoneList:TObjectList;
	FContextProcedures:TThreadProcedures;
	FDemandMode:Boolean;
	FComparer:TTaskComparer;
	FTasksSorted:Boolean;
	FDynamicTerminateEnabled:Boolean;
	FWorkers:TWorkerList;
	FTasks:TTaskList;
	FTasksLock:TMultiReadExclusiveWriteSynchronizer;
	FConcurrentWorkersCount:Integer;
	FSpareWorkersCount:Integer;

	function GetOwner(Owner:TObject; AutoAdd:Boolean = TRUE):TOwner;
	procedure UnregisterOwner(Owner:TObject);
	procedure OwnerAddTasksCount(Owner:TObject; AddTotalCount, AddDoneCount:Integer;
		FireEvents:Boolean = TRUE);
	procedure AddOwnerDone(Owner:TObject);
	procedure StoreOwners;

	procedure SetSortTasks(SortTasks:Boolean);
	function GetSortTasks:Boolean;

	property Owners:TOwnerList read FOwners;
	{**
	 * @see TPoolManager.RegisterSingletonOnDemandProc
	 *}
	property DemandMode:Boolean read FDemandMode;
{**
 * Protected section for class related stuff
 *}
protected

	class destructor Destroy;

	class procedure SingletonTerminateGate(Sender:TObject);
	{**
	 * WorkerClass should return the class of the corresponding TPoolWorker
	 *
	 * This is the one and only method, which you _must_ implement in any derived manager.
	 *
	 * Example:
	 * <code>
	 * TMyManager = class(TPoolManager)
	 * protected
	 *   class function WorkerClass:TPoolWorkerClass; override;
	 * end;
	 *
	 * implementation
	 *
	 * class function TMyManager.WorkerClass:TPoolWorkerClass;
	 * begin
	 *   Result:=TMyWorker;
	 * end;
	 * </code>
	 *}
	class function WorkerClass:TPoolWorkerClass; virtual; abstract;
{**
 * Protected section for object related stuff
 *}
protected
	procedure BeginReadTasks;
	procedure EndReadTasks;

	function BeginWriteTasks:Boolean;
	procedure EndWriteTasks;

	function GetTaskIndex(State:TTaskState; StartIndex:Integer):Integer;
	function GetSameTaskIndex(CompareTask:TPoolTask; StartIndex:Integer):Integer;

	function CreateWorker:TPoolWorker; virtual;

	procedure CustomTaskCancel(CompareFunction:TTaskFunc);
	function CustomTaskExists(CompareFunction:TTaskFunc):Boolean;
	function CustomTaskCounter(CompareFunction:TTaskFunc):Integer;

	procedure WorkerTerminated(TerminatedWorker:TPoolWorker); virtual;
	procedure WorkerTaskDone(DoneWorker:TPoolWorker; WorkerState:TWorkerState); virtual;

	procedure ExecutionLoopInitialize; override;
	function ExecutionLoopCondition:Boolean; override;
	procedure ExecutionLoop; override;
	procedure ExecutionLoopFinalize; override;

	procedure SetConcurrentWorkersCount(ConcurrentWorkersCount:Integer);
	procedure SetConcurrentWorkersCountPerCPU(ConcurrentWorkersCountPerCPU:Integer);

	procedure SetSpareWorkersCount(SpareWorkersCount:Integer);
	procedure SetSpareWorkersCountPerCPU(SpareWorkersCountPerCPU:Integer);

	property Workers:TWorkerList read FWorkers;
	property Tasks:TTaskList read FTasks;
	{**
	 * Defines, whether the tasks should be sorted, before the next is picked for processing
	 *
	 * How the tasks are sorted, must be implemented in the class method TPoolTask.Compare.
	 * If you need such sorting mechanism, you must set this property to TRUE in the
	 * derived constructor.
	 *
	 * @see TPoolTask.Compare
	 * @default FALSE
	 *}
	property SortTasks:Boolean read GetSortTasks write SetSortTasks;
	property ContextProcedures:TThreadProcedures read FContextProcedures;
{**
 * Class related public section
 *}
public
	class function Singleton:TPoolManager;
	class function HasSingleton:Boolean;
	class procedure TerminateSingletonInstances(Wait:Boolean = TRUE);

	class procedure RegisterSingletonOnDemandProc(DemandProc:TManagerProc);
	class function HasSingletonOnDemandProc:Boolean;
	class procedure UnregisterSingletonOnDemandProc;

	class procedure DispatchOwnerDestroyed(Owner:TObje
  • 25
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
智慧校园建设方案旨在通过信息化手段提升教育、管理和服务水平,实现资源数字化、工作流程化、管理高效化和决策智能化。方案包括智慧校园信息化平台和安防平台的建设,涉及教学、科研、管理和服务等多个方面,以满足现代教育和培训需求。 技术服务要求强调了统一支撑平台的建设,包括数据标准、接口标准、代码标准和用户信息标准的统一制定。平台需满足信创和X86交叉适配要求,确保安全自主可控的系统开发环境。此外,方案还涵盖了用户中心系统、统一认证授权中心、统一工作流中心、统一智能报表中心等多个模块,以及数据共享中心、语音识别、移动服务终端等功能,以实现校园内外部信息的互联互通和资源共享。 智慧校园信息化平台的建设还包括了对教学管理、人事管理、公文管理、档案管理、即时通讯、会议管理、督办工作、资产管理等方面的数字化和自动化升级。这些模块的集成旨在提高工作效率,优化资源配置,加强监督管理,并通过移动应用等技术手段,实现随时随地的信息访问和业务处理。 安防平台的建设则侧重于校园安全,包括停车场管理、人脸识别测温、访客自助登记、视频监控等多个系统。这些系统的集成旨在提高校园的安全管理水平,实现对校园内外人员和车辆的有效监控和管理,确保校园环境的安全稳定。 最后,方案还提到了对固定资产的管理,包括购置、使用、归还、报废等全生命周期的管理,以及对网络设备、安防设备、服务器等硬件设施的配置和管理。通过这些措施,智慧校园建设方案旨在为校园提供一个安全、高效、便捷的学习和工作环境。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大龙软件研发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值