Gotowego rozwiązania nie podam bo siedzę na telefonie ale do wątków pod Delphi proponowałbym Omni Thread Library. Ciężko mi teraz szukać ale jest masa przykładów i bogata dokumentacja. Zerknij tutaj
http://www.omnithreadlibrary.com/book/chap08.html
Ostatecznie zrezygnowałem z użycia Parallel.for bo zawiera błędy. Sekcje krytyczne też dawały nieprawidłowy wynik. Wynik udało mi się uzyskać z użyciem TThread. Każdy wątek dostał osobną zmienną globalną do wyprowadzenia wyników, następnie połączyłem wyniki z wątków. Dla czterech rdzeni przyspieszenie czasu przebiegu jest czterokrotne. Jeżeli już mamy program zoptymalizowany pod względem czasu wykonania, używamy najlepszego algorytmu (nie tak jak w moim przypadku kiedy się walnąłem o prostą rzecz i czas wykonania zwiększył się tysiąc razy), to możemy jeszcze użyć przyspieszenie kilkukrotnego w zależności od tego ile mamy rdzeni. Problem jest tylko z tym, że muszę powielać kod dla każdego wątku osobno. Po raz pierwszy mój program użył prawie 100% mocy procesora!! Wcześniej dochodził tylko do 25% bo działał na jednym wątku.** Ucieszyło mnie to**.
Tutaj jest ogólny schemat jak to zrobić. Podaję to bo może się komuś przydać.
procedure TForm1.MyButtonClick(Sender: TObject);
var
tasks: array of ITask;
i,k,: Integer;
wynikiRdzeni: array [1..4]of wynik; //cztery wątki
maks: wynik;
begin
Setlength (tasks ,4) //w zależności od ilości rdzeni procesora
tasks[0] := TTask.Create (procedure ()
begin
tu dać fragment pętli,
obliczenia i wyprowadzenie wartości do zmiennej globalnej wynikiRdzeni[1]
end);
tasks[0].Start;
tasks[1] := TTask.Create (procedure ()
begin
tu dac kolejny fragment pętli
obliczenia i wyprowadzenie wartości do zmiennej globalnej wynikiRdzeni[2]
end);
tasks[1].Start;
tasks[2] := TTask.Create (procedure ()
begin
tu dac kolejny fragment pętli
obliczenia i wyprowadzenie wartości do zmiennej globalnej wynikiRdzeni[3]
end);
tasks[2].Start;
tasks[3] := TTask.Create (procedure ()
begin
tu dac kolejny fragment pętli
obliczenia i wyprowadzenie wartości do zmiennej globalnej wynikiRdzeni[4]
end);
tasks[3].Start;
TTask.WaitForAll(tasks);
tu dokonujemy obliczeń połaczenia wyników tablic
a tu jest cały program
uses
system.threading, math;
type
podziałLiczby= array[0..9] of integer;
zakresy= array[1..4] of record
dół, góra: int64
end;
wynik= array[0..9] of record
ileCyfr: integer;
liczba: int64
end;
function podzielNaZakresy(a,b: int64): zakresy; //dzieli zakres pętli for dla rozłożenia na cztery rdzenie procesora
var
i, iloraz: int64;
wynik: zakresy;
begin
iloraz:= (b-a+1)div 4;
for i := 1 to 4 do
begin
wynik[i].dół:= (i-1)*iloraz+a;
if i<4
then
wynik[i].góra:= (i-1)*iloraz+a+iloraz-1
else
wynik[i].góra:= b;
end;
result:=wynik
end;
function rozłóżLiczbę(i: int64):podziałLiczby; //liczy wystąpienia cyfr w liczbie
var
k,c : integer;
s: string;
temp: podziałLiczby;
begin
for k := 0 to 9 do
temp[k]:= 0;
s:=IntToStr(i);
for k:= 0 to 9 do
begin
c:= StrToInt(s[k+1]);
temp[c]:= temp[c]+1;
end;
result:= temp;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
maks: wynik;
wynikiRdzeni: array[1..4] of wynik;
zakresyRdzeni: zakresy;
tasks: array of ITask;
i,k: int64;
hours, minutes, seconds, millisec: word;
start,koniec,timeDiff: tdatetime;
begin
start:= now;
for i:=0 to 9 do
maks[i].ileCyfr:= 0;
for i := 1 to 4 do
for k := 0 to 9 do
wynikiRdzeni[i,k].ileCyfr:=0;
Setlength(tasks ,4);
zakresyRdzeni:= podzielNaZakresy(1000000000,9999999999);
tasks[0]:= TTask.Create (procedure ()
var
temp: podziałLiczby;
i,k: int64;
begin
For i:= zakresyRdzeni[1].dół to zakresyRdzeni[1].góra do
begin
if sqr(round(sqrt(i))) = i
then
begin
temp:= rozłóżLiczbę(i);
for k:= 0 to 9 do
if temp[k]> wynikiRdzeni[1,k].ileCyfr
then
begin
wynikiRdzeni[1,k].ileCyfr:= temp[k];
wynikiRdzeni[1,k].liczba:= i
end;
end;
end
end);
tasks[0].Start;
tasks[1]:= TTask.Create (procedure ()
var
temp: podziałLiczby;
i,k: int64;
begin
For i:= zakresyRdzeni[2].dół to zakresyRdzeni[2].góra do
begin
if sqr(round(sqrt(i))) = i
then
begin
temp:= rozłóżLiczbę(i);
for k:= 0 to 9 do
if temp[k]> wynikiRdzeni[2,k].ileCyfr
then
begin
wynikiRdzeni[2,k].ileCyfr:= temp[k];
wynikiRdzeni[2,k].liczba:= i
end;
end;
end
end);
tasks[1].Start;
tasks[2]:= TTask.Create (procedure ()
var
temp: podziałLiczby;
i,k: int64;
begin
For i:= zakresyRdzeni[3].dół to zakresyRdzeni[3].góra do
begin
if sqr(round(sqrt(i))) = i
then
begin
temp:= rozłóżLiczbę(i);
for k:= 0 to 9 do
if temp[k]> wynikiRdzeni[3,k].ileCyfr
then
begin
wynikiRdzeni[3,k].ileCyfr:= temp[k];
wynikiRdzeni[3,k].liczba:= i
end;
end;
end
end);
tasks[2].Start;
tasks[3]:= TTask.Create (procedure ()
var
temp: podziałLiczby;
i,k: int64;
begin
For i:= zakresyRdzeni[4].dół to zakresyRdzeni[4].góra do
begin
if sqr(round(sqrt(i))) = i
then
begin
temp:= rozłóżLiczbę(i);
for k:= 0 to 9 do
if temp[k]> wynikiRdzeni[4,k].ileCyfr
then
begin
wynikiRdzeni[4,k].ileCyfr:= temp[k];
wynikiRdzeni[4,k].liczba:= i
end;
end;
end
end);
tasks[3].Start;
TTask.WaitForAll(tasks);
//zbieramy dane z wątków razem
for i:= 0 to 9 do
for k:=1 to 4 do
if wynikiRdzeni[k,i].ileCyfr>maks[i].ileCyfr
then
begin
maks[i].ileCyfr:= wynikiRdzeni[k,i].ileCyfr;
maks[i].liczba:= wynikiRdzeni[k,i].liczba
end;
koniec:= now;
timeDiff:= koniec - start;
DecodeTime(timeDiff, hours, minutes, seconds, millisec);
memo1.Lines.Add('godziny='+IntToStr(hours));
memo1.Lines.Add('minuty='+IntToStr(minutes));
memo1.Lines.Add('sekundy='+IntToStr(seconds));
memo1.Lines.Add('milisekundy='+IntToStr(millisec));
for k:= 0 to 9 do
if maks[k].ileCyfr > 0
then
memo1.Lines.Add('najwięcej cyfr dla '+IntToStr(k)+' wynosi '+
IntToStr(maks[k].ileCyfr)+' dla '+IntToStr(maks[k].liczba))
end;