Fixed concurrent processing
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user