Difference between revisions of "Parallel procedures/de"

From Free Pascal wiki
Jump to navigationJump to search
m
Line 1: Line 1:
 
{{Parallel_procedures}}
 
{{Parallel_procedures}}
= Übersicht =
 
  
Diese Seite beschreibt wie man eine einzelen Prozedur parallel laufen lässt unter Benutzung der MTProcs Unit, welche das parallel laufen lassen und die Implementierung von parallelen Algorithmen vereinfacht.
+
== Übersicht ==
  
Parallele Prozeduren und Methoden werden oft in parallele Algorithmen gefunden und eiinige Programmiersprachen haben einen eingebauten Support für sie (z.B. OpenMP im gcc). Siehe auch [[OpenMP support|hier]] für die Planung der Hinzufügung dieser Sprachfeatures im FPC. Einbetten dieser Sachen in die Sprache kann zur Reduzierung von Eingaben führen und erlaubt dem Kompiler Kode zu erzeugen, der weniger Overhead hat. Auf der anderen Seite ist hier kein einfacher alorithmus um Kode parallel laufen zu lassen. Tatsächlich machen einfache Versuche oft den Kode langsamer. Um gute Resultate zu erhalten, muß man einige Parameter spezifizieren, welche der Kompiler nicht voraussagen kann. Als Beispiel kann man sich die unermässliche Anzahl an Einstellungen und Diskussionen auf [http://openmp.org/wp/ OpenMP] ansehen. Man benötigt parallele Algorithmen. MTProcs hilft bei der Implementierung von parallelen Algorithmen.
+
Diese Seite beschreibt, wie man eine einzelne Prozedur parallel laufen lässt unter Benutzung der MTProcs Unit, welche das parallel laufen lassen und die Implementierung von parallelen Algorithmen vereinfacht.
  
= MTProcs erhalten=
+
Parallele Prozeduren und Methoden werden oft in parallele Algorithmen gefunden und eiinige Programmiersprachen haben einen eingebauten Support für sie (z.B. OpenMP im gcc). Siehe auch [[OpenMP support|hier]] für die Planung der Hinzufügung dieser Sprachfeatures im FPC. Einbetten dieser Sachen in die Sprache kann zur Reduzierung von Eingaben führen und erlaubt dem Compiler Code zu erzeugen, der weniger Overhead hat. Auf der anderen Seite ist hier kein einfacher Algorithmus, um Code parallel laufen zu lassen. Tatsächlich machen einfache Versuche oft den Code langsamer. Um gute Resultate zu erhalten, muß man einige Parameter spezifizieren, welche der Compiler nicht voraussagen kann. Als Beispiel kann man sich die unermessliche Anzahl an Einstellungen und Diskussionen auf [http://openmp.org/wp/ OpenMP] ansehen. Man benötigt parallele Algorithmen. MTProcs hilft bei der Implementierung von parallelen Algorithmen.
  
Die Unit '''mtprocs.pas''' ist ein Teil des '''multithreadprocslaz.lpk''' Paket, welches via svn von
+
== MTProcs erhalten ==
 +
 
 +
Die Unit '''mtprocs.pas''' ist ein Teil des '''multithreadprocslaz.lpk''' Paket, welches mittels svn von
 
<pre>
 
<pre>
 
svn co https://lazarus-ccr.svn.sourceforge.net/svnroot/lazarus-ccr/components/multithreadprocs multithreadprocs  
 
svn co https://lazarus-ccr.svn.sourceforge.net/svnroot/lazarus-ccr/components/multithreadprocs multithreadprocs  
Line 17: Line 18:
 
Um das Paket in deinem Projekt zu verwenden: Benutze ''IDE Menu / Package / Open recent package / .../multithreadprocslaz.lpk / More / add to project'' um es in deinem aktuellen Projekt zu verwenden. Oder füge mittels des Projekt Inspektiors hinzu.
 
Um das Paket in deinem Projekt zu verwenden: Benutze ''IDE Menu / Package / Open recent package / .../multithreadprocslaz.lpk / More / add to project'' um es in deinem aktuellen Projekt zu verwenden. Oder füge mittels des Projekt Inspektiors hinzu.
  
= Einfaches Beispiel =
+
== Einfaches Beispiel ==
  
 
Hier ist ein einfaches Beispiel, welches nichts wirklich sinnvolles macht, um zu zeigen wie parallele Prozeduren aussehen und wie sie aufgerufen werden:
 
Hier ist ein einfaches Beispiel, welches nichts wirklich sinnvolles macht, um zu zeigen wie parallele Prozeduren aussehen und wie sie aufgerufen werden:
Line 65: Line 66:
 
*Die Ausgabe zeigt den typischen multithreading Fall: Die Reihenfolge der Aufrufe ist nicht vorhersehbar. Verschieden Läufe können Ergebnisse in unterschiedlicher Reihenfolge haben.
 
*Die Ausgabe zeigt den typischen multithreading Fall: Die Reihenfolge der Aufrufe ist nicht vorhersehbar. Verschieden Läufe können Ergebnisse in unterschiedlicher Reihenfolge haben.
  
= Features =
+
== Features ==
  
 
Running a procedure in parallel means:
 
Running a procedure in parallel means:
Line 77: Line 78:
 
*Threads are reused, that means they are not destroyed and created for each index, but there is a global pool of threads. On a dual core processor there will be two threads doing all the work - the main thread and one extra thread in the pool.
 
*Threads are reused, that means they are not destroyed and created for each index, but there is a global pool of threads. On a dual core processor there will be two threads doing all the work - the main thread and one extra thread in the pool.
  
= Overhead, slow down =
+
== Overhead, slow down ==
  
 
The overhead heavily depends on the system (number and types of cores, type of shared memory, speed of critical sections, cache size). Here are some general hints:
 
The overhead heavily depends on the system (number and types of cores, type of shared memory, speed of critical sections, cache size). Here are some general hints:
Line 90: Line 91:
 
*Do not work on vast amounts of memory. On some systems one thread alone is fast enough to fill the memory bus speed. When the memory bus maximum speed is reached, any further thread will slow down instead of making it faster.
 
*Do not work on vast amounts of memory. On some systems one thread alone is fast enough to fill the memory bus speed. When the memory bus maximum speed is reached, any further thread will slow down instead of making it faster.
  
= Setting the maximum number of threads for a procedure =
+
== Setting the maximum number of threads for a procedure ==
  
 
You can specify the maximum number of threads for a procedure as the fifth parameter.
 
You can specify the maximum number of threads for a procedure as the fifth parameter.
Line 103: Line 104:
 
This can be useful, when the threads work on the same data, and a too many threads will create so many cache conflicts, that they slow down each other. Or when the algorithm uses a lot of WaitForIndex, so that only a few threads can actually work. Then the threads can be used for other tasks.
 
This can be useful, when the threads work on the same data, and a too many threads will create so many cache conflicts, that they slow down each other. Or when the algorithm uses a lot of WaitForIndex, so that only a few threads can actually work. Then the threads can be used for other tasks.
  
= Wait for index / executing in order =
+
== Wait for index / executing in order ==
  
 
Sometimes an Index depends on the result of a former Index. For example a common task is to first compute chunk 5 and then combine the result with the result of chunk 3. Use the WaitForIndex method for that:
 
Sometimes an Index depends on the result of a former Index. For example a common task is to first compute chunk 5 and then combine the result with the result of chunk 3. Use the WaitForIndex method for that:
Line 120: Line 121:
 
WaitForIndex takes as an argument an Index that is lower than the current Index or a range. If it returns true, everything worked as expected. If it returns false, then an exception happened in one of the other threads.
 
WaitForIndex takes as an argument an Index that is lower than the current Index or a range. If it returns true, everything worked as expected. If it returns false, then an exception happened in one of the other threads.
  
= Exceptions =
+
== Exceptions ==
  
 
If an exception occur in one of the threads, the other threads will finish normally, but will not start a new Index. The pool waits for all threads to finish and will then raise the exception. That's why you can use ''try..except'' like always:
 
If an exception occur in one of the threads, the other threads will finish normally, but will not start a new Index. The pool waits for all threads to finish and will then raise the exception. That's why you can use ''try..except'' like always:

Revision as of 22:12, 12 May 2009

Deutsch (de) English (en) 日本語 (ja) русский (ru)

Übersicht

Diese Seite beschreibt, wie man eine einzelne Prozedur parallel laufen lässt unter Benutzung der MTProcs Unit, welche das parallel laufen lassen und die Implementierung von parallelen Algorithmen vereinfacht.

Parallele Prozeduren und Methoden werden oft in parallele Algorithmen gefunden und eiinige Programmiersprachen haben einen eingebauten Support für sie (z.B. OpenMP im gcc). Siehe auch hier für die Planung der Hinzufügung dieser Sprachfeatures im FPC. Einbetten dieser Sachen in die Sprache kann zur Reduzierung von Eingaben führen und erlaubt dem Compiler Code zu erzeugen, der weniger Overhead hat. Auf der anderen Seite ist hier kein einfacher Algorithmus, um Code parallel laufen zu lassen. Tatsächlich machen einfache Versuche oft den Code langsamer. Um gute Resultate zu erhalten, muß man einige Parameter spezifizieren, welche der Compiler nicht voraussagen kann. Als Beispiel kann man sich die unermessliche Anzahl an Einstellungen und Diskussionen auf OpenMP ansehen. Man benötigt parallele Algorithmen. MTProcs hilft bei der Implementierung von parallelen Algorithmen.

MTProcs erhalten

Die Unit mtprocs.pas ist ein Teil des multithreadprocslaz.lpk Paket, welches mittels svn von

svn co https://lazarus-ccr.svn.sourceforge.net/svnroot/lazarus-ccr/components/multithreadprocs multithreadprocs 

heruntergeladen werden kann.

Wie immer: Öffne das Paket multithreadprocslaz.lpk einmal in der IDE, so das es die Pfade lernt. Um das Paket in deinem Projekt zu verwenden: Benutze IDE Menu / Package / Open recent package / .../multithreadprocslaz.lpk / More / add to project um es in deinem aktuellen Projekt zu verwenden. Oder füge mittels des Projekt Inspektiors hinzu.

Einfaches Beispiel

Hier ist ein einfaches Beispiel, welches nichts wirklich sinnvolles macht, um zu zeigen wie parallele Prozeduren aussehen und wie sie aufgerufen werden:

<Delphi> program Test;

{$mode objfpc}{$H+}

uses

 {$IFDEF UNIX}
 cthreads, cmem,
 {$ENDIF}
 MTProcs;

// a simple parallel procedure procedure DoSomethingParallel(Index: PtrInt; Data: Pointer; Item: TMultiThreadProcItem); var

 i: Integer;

begin

 writeln(Index);
 for i:=1 to Index*1000000 do ; // do some work

end;

begin

 ProcThreadPool.DoParallel(@DoSomethingParallel,1,5,nil); // address, startindex, endindex, optional data

end. </Delphi>

Die Ausgabe wird ähnlich wie folgendes sein:

2
3
1
4
5

Hier einige kurze Anmerkungen. Die Details folgen später

  • Multithreading benötigt unter Unix die Unit cthreads wie im Multithreaded Application Tutorial/de erklärt.
  • Aus Geschwindigkeitsgründen wird der cmem Heapmanager empfohlen, aber hier für dieses Beispiel macht es keinen Unterschied.
  • Die paralle Prozdur DoSomethingParallelerhält einige fixe und vordefinierte Parameter.
  • Index definiert, welchen Teil der Arbeit in diesem Aufruf gemacht werden soll.
  • Data ist ein Zeiger, welcher ProcThreadPool.DoParallel als vierter Parameter übergeben wird. Er ist optional und man ist frei ob man ihn für irgendwas benutzt.
  • Item kann für den Zugriff auf mehr verfeinerte Features des Threadpools verwendet werden.
  • ProcThreadPool.DoParallel arbeitet wie ein normaler Prozeduraufruf. Er kommt zurück, wenn er komplett abgearbeitet wurde - das heisst, alle Thread haben ihre arbeit beendet.
  • Die Ausgabe zeigt den typischen multithreading Fall: Die Reihenfolge der Aufrufe ist nicht vorhersehbar. Verschieden Läufe können Ergebnisse in unterschiedlicher Reihenfolge haben.

Features

Running a procedure in parallel means:

  • a procedure or method is executed with an Index running from an arbitrary StartIndex to an arbitrary EndIndex.
  • One or more threads execute these index' in parallel. For example if the Index runs from 1 to 10 and there are 3 threads available in the pool, then 3 threads will run three different index at the same time. Every time a thread finishes one call (one index) it allocates the next index and runs it. The result may be: Thread 1 executes index 3,5,7, thread 2 executes 1,6,8,9 and thread 3 runs 2,4,10.
  • The number of threads may vary during run and there is no guarantee for a minimum of threads. In the worst case all index will be executed by one thread - the thread itself.
  • The maximum number of threads is initialized with a good guess for the current system. It can be manually set at any time via
 ProcThreadPool.MaxThreadCount:=8;
  • You can set the maximum threads for each procedure.
  • A parallel procedure (or method) can call recursively parallel procedures (or methods).
  • Threads are reused, that means they are not destroyed and created for each index, but there is a global pool of threads. On a dual core processor there will be two threads doing all the work - the main thread and one extra thread in the pool.

Overhead, slow down

The overhead heavily depends on the system (number and types of cores, type of shared memory, speed of critical sections, cache size). Here are some general hints:

  • Each chunk of work (index) should take at least some milliseconds.
  • The overhead is independent of recursive levels of parallel procedures.

Multi threading overhead, which is independent of the MTProcs units, but simply results from todays computer architectures:

  • As soon as one thread is created your program becomes multi threaded and the memory managers must use critical sections, which slows down. So even if you do nothing with the thread your program might become slower.
  • The cmem heap manager is on some systems much faster for multi threading. In my benchmarks especially on intel systems and especially under OS X the speed difference can be more than 10 times.
  • Strings and interfaces are globally reference counted. Each access needs a critical section. Processing strings in multiple threads will therefore hardly give any speed up. Use PChars instead.
  • Each chunk of work (index) should work on a disjunctive part of memory to avoid cross cache updates.
  • Do not work on vast amounts of memory. On some systems one thread alone is fast enough to fill the memory bus speed. When the memory bus maximum speed is reached, any further thread will slow down instead of making it faster.

Setting the maximum number of threads for a procedure

You can specify the maximum number of threads for a procedure as the fifth parameter.

<Delphi> begin

 ProcThreadPool.DoParallel(@DoSomethingParallel,1,10,nil,2); // address, startindex, endindex, 
     // optional: data (here: nil), optional: maximum number of threads (here: 2)

end. </Delphi>

This can be useful, when the threads work on the same data, and a too many threads will create so many cache conflicts, that they slow down each other. Or when the algorithm uses a lot of WaitForIndex, so that only a few threads can actually work. Then the threads can be used for other tasks.

Wait for index / executing in order

Sometimes an Index depends on the result of a former Index. For example a common task is to first compute chunk 5 and then combine the result with the result of chunk 3. Use the WaitForIndex method for that:

<Delphi> procedure DoSomethingParallel(Index: PtrInt; Data: Pointer; Item: TMultiThreadProcItem); begin

 ... compute chunk number 'Index' ...
 if Index=5 then begin
   if not Item.WaitForIndex(3) then exit;
   ... compute ...
 end;

end; </Delphi>

WaitForIndex takes as an argument an Index that is lower than the current Index or a range. If it returns true, everything worked as expected. If it returns false, then an exception happened in one of the other threads.

Exceptions

If an exception occur in one of the threads, the other threads will finish normally, but will not start a new Index. The pool waits for all threads to finish and will then raise the exception. That's why you can use try..except like always:

<Delphi> try

 ...
 ProcThreadPool.DoParallel(...);
 ...

except

 On E: Exception do ...

end; </Delphi>

If there are multiple exceptions, only the first exception will be raised. To handle all exceptions, add a try..except inside your parallel method.