Random and Multithreading



Hello,

I have to apply a graphic filter on a Bitmap.

I have a corde 2 duo since a few weeks so I decided to port this filter to multithreading, and I was very surprised that it takes more time in multithreading than normal.
After spending some times on my code I have discovered that the bottleneck was the random function.

So i have made a small example that do only random, and i was a lot surpised.

here's the result for doing 48000000 randoms on my core 2 duo :

Normal : 204 ms
Multithread (2 threads) : 1109 ms.

so My questtions are :
- Am I missing something ?
- Is there any alternative to RTL random that support better and faster random ?


here's the code :

Type
TRandom = class(TThread)
private
FCount: Integer;
protected
procedure Execute; override;
public
constructor Create(Count: integer; Suspended: Boolean);
end;


//The threaded random Class
constructor TRandom.Create(Count: integer; Suspended: Boolean);
begin
FreeOnTerminate := False;
inherited Create(Suspended);
FCount := Count;
end;

procedure TRandom.Execute;
var
i, j: integer;
begin
for i := 0 to FCount - 1 do
j := random(255);
end;

//the way it is called
procedure DoRandom(Count: integer; NbThreads: integer);
var
threads: array of THandle;
ft: array of TRandom;
i, j, NBCountThread, Lastthread, NBC: integer;
begin
try

//Number of count per thread
NBCountThread := Count div NbThreads;
Lastthread := NbThreads - 1;

SetLength(threads, NbThreads);
SetLength(ft, NbThreads);
j := 0;
// start all threads
for i := 0 to high(threads) {Lastthread} do
begin
if i < Lastthread then
begin
//Number of count for this thread
NBC := NBCountThread;
inc(j, nbc);
end
else
begin
//Number of count for last thread
NBC := Count - j;
end;
ft[i] := TRandom.Create(NBC, True);
// store handle of the thread so we know what to wait for
threads[i] := ft[i].Handle;
ft[i].Resume;
end;

// wait until all threads are done
WaitForMultipleObjects(NbThreads, @threads[0], true, INFINITE);
finally
for i := 0 to high(ft) do
if Ft[i] <> nil then
FreeAndNil(Ft[i]);
SetLength(ft, 0);
SetLength(Threads, 0);
end;
end;


//the same thing without multithreading
procedure NormalRandom(FCount: integer);
var
i, j: integer;
begin
for i := 0 to FCount - 1 do
j := random(255);
end;


//the test
procedure TForm1.Button2Click(Sender: TObject);
var
TC: integer;
begin
tc := Gettickcount;
NormalRandom(48000000);
tc := Gettickcount - tc;
Showmessage(inttostr(tc));

tc := Gettickcount;
DoRandom(48000000,2); //2 threads
tc := Gettickcount - tc;
Showmessage(inttostr(tc));
end;



thanks

John
.