Fixed concurrent processing

This commit is contained in:
Michael Schimmel
2025-07-16 14:12:07 +02:00
parent bc75f08477
commit 342eb07c42
8 changed files with 192 additions and 105 deletions
+69 -11
View File
@@ -4,6 +4,7 @@ interface
uses
System.SysUtils,
System.SyncObjs,
Myc.Signals,
Myc.Mutable,
Myc.Core.Notifier,
@@ -15,6 +16,7 @@ type
// Abstract base class for data consumers.
TMycProcessor<T> = class abstract(TInterfacedObject, IMycProcessor<T>)
protected
function Execute(const Value: T; const Proc: TConstFunc<T, TState>): TState;
function ProcessData(const Value: T): TState; virtual; abstract;
end;
@@ -86,7 +88,16 @@ type
constructor Create(const AFunc: TConstFunc<S, T>);
end;
// A converter specialized for calculating indicators.
TMycGenericParallelConverter<S, T> = class(TMycConverter<S, T>)
private
FFunc: TConstFunc<S, T>;
FQueue: TState;
protected
function ProcessData(const Value: S): TState; override;
public
constructor Create(const AFunc: TConstFunc<S, T>);
end;
TMycIdentityConverter<T> = class(TMycConverter<T, T>)
protected
function ProcessData(const Value: T): TState; override; final;
@@ -126,14 +137,12 @@ type
// A generic processor implementation that uses a function reference.
TMycGenericProcessor<T> = class(TMycProcessor<T>)
type
TProc = reference to function(const Value: T): TState;
private
FProc: TProc;
FProc: TConstFunc<T, TState>;
protected
function ProcessData(const Value: T): TState; override; final;
public
constructor Create(const AProc: TProc);
constructor Create(const AProc: TConstFunc<T, TState>);
end;
// A processor implementation that is owned by a controller.
@@ -156,6 +165,7 @@ type
FLookback: Int64;
FData: TSeries<T>;
FChanged: TEvent;
FLock: TLightweightMREW;
function GetChanged: TSignal;
function GetValue: TSeries<T>;
function ProcessData(const Value: T): TState;
@@ -178,6 +188,13 @@ type
property Timeframe: TTimeframe read GetTimeframe;
end;
TMycParallelConverter<T> = class(TMycConverter<T, T>)
private
FQueue: TState;
protected
function ProcessData(const Value: T): TState; override; final;
end;
implementation
uses
@@ -187,6 +204,14 @@ uses
System.Math,
Myc.TaskManager;
{ TMycProcessor<T> }
function TMycProcessor<T>.Execute(const Value: T; const Proc: TConstFunc<T, TState>): TState;
begin
var cValue := Value;
Result := TaskManager.RunTask(function: TState begin Result := Proc(cValue); end);
end;
{ TMycContainedDataProvider<T> }
constructor TMycContainedDataProvider<T>.Create(const Controller: IInterface);
@@ -314,7 +339,7 @@ end;
function TMycIndicator<S, T>.ProcessData(const Value: S): TState;
begin
Result := Broadcast(Calculate(Value));
Result := Execute(Value, function(const Value: S): TState begin Result := Broadcast(Calculate(Value)); end);
end;
{ TMycDataCounter<T> }
@@ -385,7 +410,7 @@ end;
{ TMycGenericProcessor<T> }
constructor TMycGenericProcessor<T>.Create(const AProc: TProc);
constructor TMycGenericProcessor<T>.Create(const AProc: TConstFunc<T, TState>);
begin
inherited Create;
FProc := AProc;
@@ -419,6 +444,7 @@ begin
FProcessor := TMycContainedProcessor<T>.Create(Self, ProcessData);
FTag := FDataProvider.Link(FProcessor);
end;
destructor TMycDataEndpoint<T>.Destroy;
@@ -435,15 +461,24 @@ end;
function TMycDataEndpoint<T>.GetValue: TSeries<T>;
begin
Result := FData;
FLock.BeginRead;
try
Result := FData;
finally
FLock.EndRead;
end;
end;
function TMycDataEndpoint<T>.ProcessData(const Value: T): TState;
begin
Result := TState.Null;
// Add new data point, respecting the lookback period.
FData := FData.Add(Value, FLookback);
FLock.BeginWrite;
try
// Add new data point, respecting the lookback period.
FData := FData.Add(Value, FLookback);
finally
FLock.EndWrite;
end;
FChanged.Notify;
end;
@@ -599,4 +634,27 @@ begin
Result := Broadcast(Value);
end;
{ TMycGenericParallelConverter<S, T> }
constructor TMycGenericParallelConverter<S, T>.Create(const AFunc: TConstFunc<S, T>);
begin
inherited Create;
FFunc := AFunc;
end;
function TMycGenericParallelConverter<S, T>.ProcessData(const Value: S): TState;
begin
var cValue := Value;
Result := TaskManager.RunTask(FQueue, function: TState begin Result := Broadcast(FFunc(cValue)); end);
FQueue := Result;
end;
function TMycParallelConverter<T>.ProcessData(const Value: T): TState;
begin
var cValue := Value;
Result := TaskManager.RunTask(FQueue, function: TState begin Result := Broadcast(cValue); end);
FQueue := Result;
end;
end.