:-) Hello :-)
Although I find mtprocs very useful, I needed something with
a lot less overhead. 1 millisecond of overhead is far beyond the tolerance in my neural network API.
So, I coded something similar. All threads are kept alive waiting for an event to start. Got some inspiration here:
http://www.paradicesoftware.com/blog/2014/02/dont-use-suspend-and-resume-but-dont-poll-either/I have a thread list with "always on" threads that are sent an event when I need them to start. This is the inner core:
procedure TNeuronThread.Execute;
begin
while (not Terminated) do
begin
FNeuronStart.WaitFor(INFINITE);
FNeuronStart.ResetEvent;
if (FShouldStart) then
begin
FRunning := true;
FShouldStart := false;
FProc(FIndex, FThreadNum);
FRunning := false;
FNeuronFinish.SetEvent;
FProcFinished := true;
end;
end;
end;
This is how the thread list is implemented:
TNeuronThreadList = class (specialize TFPGObjectList<TNeuronThread>)
private
FStarted: boolean;
public
constructor Create(pSize: integer);
procedure StartEngine();
procedure StopEngine();
procedure StartProc(pProc: TNeuronProc; pBlock: boolean = true);
procedure WaitForProc(); {$IFDEF Release} inline; {$ENDIF}
end;
When creating the list, all threads are created:
constructor TNeuronThreadList.Create(pSize: integer);
var
I: integer;
begin
inherited Create(true);
FStarted := false;
for I := 1 to pSize do
begin
Self.Add( TNeuronThread.Create(true, I));
end;
end;
The waiting is implemented via events:
procedure TNeuronThread.WaitForProc();
begin
FNeuronFinish.WaitFor(INFINITE);
FNeuronFinish.ResetEvent;
end;
All threads are launched together with:
procedure TNeuronThreadList.StartProc(pProc: TNeuronProc; pBlock: boolean = true);
var
I: integer;
localCount: integer;
begin
localCount := Count;
if not(FStarted) then StartEngine();
for I := 0 to localCount - 1 do
begin
Self.Items[I].StartProc(pProc, I, localCount);
end;
if pBlock then WaitForProc();
end;
USAGEThis was the original code:
for I := 0 to FNeurons.Count - 1 do
begin
ComputeNeuronFast(I);
end;
This is the new parallel code:
procedure TNNetConvolution.ComputeNTL(index, threadnum: integer);
var
I: integer;
begin
for I := 0 to FNeurons.Count - 1 do
begin
if I mod threadnum = index then
begin
ComputeNeuronFast(I);
end;
end;
end;
...
fNTL.StartProc(@ComputeNTL); // calls above code
The full source code is located here:
https://sourceforge.net/p/cai/svncode/HEAD/tree/trunk/lazarus/libs/ntl.pas:-) Wish everyone happy coding :-)