Laden...

Parallel processing mit durch mehrere threads?

Erstellt von Konin vor 10 Jahren Letzter Beitrag vor 10 Jahren 2.898 Views
K
Konin Themenstarter:in
4 Beiträge seit 2013
vor 10 Jahren
Parallel processing mit durch mehrere threads?

Hallo liebe C# Community,

ich habe eine etwas speziellere Frage und möchte euch zunächst mal einen kleinen Einblick geben in das Projekt das ich momentan verfolge.

Ich schreibe momentan an einer PixelBotAPI. Teil dieser API sind methoden die aus einem geöffneten Anwendungsfenster einen Screenshot macht und das so erhaltene Bild runterskaliert. Das ganze mache ich mehrmals die Sekunde. Die Screenshots werden paarweise verglichen und über einen relativ simplen Motion detect algorithmus lasse ich mir bewegliche Objekt in dem Spiel in einem Schwar-weiß Bild anzeigen (so finde ich heraus wo sich angreifbare Monster auf dem Bildschirm befinden). Außerdem wird über ein Graustufenbild das ich mit einer energyfunction ausrechne, Kanten von Spielgrafiken ermittelt, sodass mein Bot später Hindernisse erkennen kann.

Das funktioniert soweit auch, die Frage die sich nun stellt ist natürlich wie ich das ganze noch optimieren kann. 😁
Leider sind meine Kenntnisse beim multithreading relativ bescheiden. Ich verstehe den grundsätzlichen Gebrauch von threads, weiss aber nicht genau wie sie auf der Maschine ausgeführt werden. 8)

Grundsätzlich war meine Idee die bitmaps die ich durch die Screenshots erhalte aufzuteilen und mit mehreren threads zu analysieren.
Die Frage ist jetzt welche threads wirklich parallel laufen? X(

Nehmen wir an ich hätte jetzt einen 4 Kern CPU. Das würde doch bedeuten ich könnte maximal 4 threads parallel ausführen und alle weiteren threads würden danach ausgeführt werden, oder?
Falls dem so ist, macht es denn dann Sinn mehr threads als CPU Kerne zu haben (aus Laufzeitsicht)?
Ist es möglich mit einem Thread einen bestimmten CPU Kern anzusteuern?
Kann man mithilfe des .net Frameworks herausfinden wieviele Kerne der Anwendung zur Verfügung stehen?

Vielen Dank!
Konin

16.835 Beiträge seit 2008
vor 10 Jahren

Zu aller erst: wir werden Dir nicht konkret helfen wenn es darum geht Spielregeln zu brechen oder Missbrauch (wie Cheats) zu fördern.
Sollte es in diese Richtung gehen werden wir das Thema schließen.

Zum Thema Parallel Programming:
unbedingt die Grundlagen von Threads (auch im Zusammenspiel mit dem Betriebssystem und dem Scheduler) verstehen und dann Parallel Programming with Microsoft .NET lesen.
Wird viel Lektüre auf Dich zukommen.

Es gibt verschiedene Möglichkeiten, aber im Prinzip ist das Pipeline-Thema die richtige Richtung.
Wirst Du aber nicht verstehen ohne die vorherigen Themen nicht verstanden zu haben. Ansonsten wirst Du recht schnell in Stolperfallen tappen.

Zur Anzahl von Thread lies Dir mal mein Kommentar in Aktionen in der GameLoop auf Threads (Mulitcores) verteilen durch (7. Betrag). Das trifft auch hier zu.
Verstehst Du wie der Scheduler einer Betriebssystems funktioniert, dann wird Dir auch klar, worauf ich hier hinaus will.

K
Konin Themenstarter:in
4 Beiträge seit 2013
vor 10 Jahren

Zu aller erst: wir werden Dir nicht konkret helfen wenn es darum geht Spielregeln zu brechen oder Missbrauch (wie Cheats) zu fördern.
Sollte es in diese Richtung gehen werden wir das Thema schließen.

Es geht nur darum eine API zu erstellen von konkreter Implementierung eines Bots ist nicht die Rede auch nicht das Ziel. Es geht uns darum wie man Bilddaten mit einem Agent automatisch verarbeiten kann...

Ich werde mir das Buch und den Beitrag mal genauer ansehen, Vielen Dank 👍

6.911 Beiträge seit 2009
vor 10 Jahren

Hallo Konin,

wie Abt schon erwähnt hat ist ein Aneignen der Grundlagen des parallelen Programmierens unerlässlich. Wenn du darin fit bist kannst du auch die Dataflow (Task Parallel Library) verwenden, denn ich denke diese eignet sich für deine Verarbeitunggschritte sehr gut. Als Lektüre passt dazu auch Introduction to TPL Dataflow - aber beschäftige dich damit wirklich erst wenn du die Grundlagen drauf hast, sonst wirst du mehr Ärger als Freude haben.

Das würde doch bedeuten ich könnte maximal 4 threads parallel ausführen und alle weiteren threads würden danach ausgeführt werden, oder?

Bei N logischen Kernen* können wirklich gleichzeitig auch nur N Threads ausgeführt werden. Das Betriebssystem und dessen Scheduler sind zuständig um die Gesamt-Menge aller Threads aus allen laufenden Prozessen auf die Kerne zu verteilen. Es ist durchaus üblich, dass im Gesamtsystem mehr Threads vorhanden sind als (logische) Kerne der CPU.

Falls dem so ist, macht es denn dann Sinn mehr threads als CPU Kerne zu haben (aus Laufzeitsicht)?

Pauschal kann das nicht beantwortet werden, denn es hängt sehr vom konkreten Anwendungsfall ab.
Als ganz grobe Regel:*Geht es um eine Aufgabe in der aufwändige Berechnungen durchgeführt werden so macht es keinen Sinn mehr Threads als Kerne zu haben, da sonst die sogenannte "Oversubscription" passiert, d.h. die Threads verdrängen sich gegenseitig von ihrer Arbeit. *Geht es um Aufgaben in IO-Zugriffe, Datenbankzugriffe, etc. stattfinden in den auf das Ergebnis dieser Zugriffe gewartet werden muss, so kann es sinnvoll sein mehr Threads als Kerne zu haben, denn während die einen Threads eh warten müssen können die anderen Threads arbeiten.

Der in .net mit der TPL eingeführte TaskScheduler (exakter der TaskScheduler für den ThreadPool) hat Algorithmen die je nach Auslastung des Systems regeln (!= steuern) wieviele Threads verwendet werden sollen. Dieser misst den "Durchsatz" und erhöht od. erniedrigt die Anzahl der verfügbaren Threads.
Somit ist es wohl am besten diesem die Verwaltung der Threads zu überlassen.
Nähere Infos dazu Concurrency - Throttling Concurrency in the CLR 4.0 ThreadPool

Ist es möglich mit einem Thread einen bestimmten CPU Kern anzusteuern?

Es ist möglich dem Thread per AffinityMask mitzuteilen, dass er zu einem bestimmten Kern affin ist, d.h. es sollte wenn es geht auf diesen Kern laufen.
Dabei pfuschst du aber dem Scheduler vom Betriebssystem ins Handwerk und es ergibt sich oft ein eher nachteiliges Ergebnis. Obs hiflt zeigt nur eine Messung - dabei berücksichtigst du aber auch nur deine Maschine und bei einer anderen kann es ganz anders ausschauen. Lass das also besser dem Betriebssystem über.

Kann man mithilfe des .net Frameworks herausfinden wieviele Kerne der Anwendung zur Verfügung stehen? Environment.ProcessorCount

mfG Gü

* im Computer sind physische Kerne verbaut, diese können aber durch Techniken wie Hyperthreading als doppelt soviele logische Kerne verfügbar gemacht werden.

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

K
Konin Themenstarter:in
4 Beiträge seit 2013
vor 10 Jahren

Super, genau das wollte ich wissen 😁

...
Ich habe mir "Parallel Programming with Microsoft .NET" genauer angeschaut und mit dem Parallel.For etwas gefunden was für mein Vorhaben maßgeschneidert ist.
Da ich Bitmaps mit zwei verschachtelten for-schleifen traversiere, kann ich die äußere von beiden Schleifen mit Parallel.for so weit wie das Betriebssystem zulässt parallelisieren.

Es kann aber wohl nicht schaden sich noch ein wenig tiefer in die parallele/nebenläufige Programmierung einzulesen 8) ,
genug Lesestoff habe ich ja nun :rtfm: :rtfm: :rtfm:

16.835 Beiträge seit 2008
vor 10 Jahren

Bedenke bei Bitmap:

Thread Safety

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

Somit dürfte ein GetPixel - sofern Du das nutzt - nicht Thread-Safe sein.
Damit ist auch der parallele Zugriff über Parallel.For() vielleicht nicht unbedingt die beste Idee.

Fazit: mit dem Thema _richtig _beschäftigen und nicht gleich die erste "neue" Sache aufnehmen und verwenden, wenn sie vllt gar nicht geeignet ist.

K
Konin Themenstarter:in
4 Beiträge seit 2013
vor 10 Jahren

Ich möchte die bitmap auch nicht als public static haben.
Mir schwebt vor eine Class BitmapManipulation zu erstellen welche im Consructor den Screenshot als bitmap übergibt und als private readonly deklariert.. Wenn ich mich nicht ganz täusche sollte doch nun mein Parallel.for seiniges tun. Da die bitmap readonly ist, ist sie threadsicher und kann parallel benutzt werden.
Die methoden die mir nun das Graustufenbild und das Schwarz-Weißbild liefern (jeweils neu erstellte bitmaps) geben das resultierende Bild als bitmap zurück.

16.835 Beiträge seit 2008
vor 10 Jahren

Da die bitmap readonly ist, ist sie threadsicher und kann parallel benutzt werden.

ääähm... nein.
readonly hat nichts mit Threadsicherheit zutun.
Also nochmal: vielleicht schaust Dir das Thema genauer an bevor Du das angehst 😉
....und vielleicht auch gleich nochmal ein kurzer Blick in die C# Grundlagen 😉

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo Abt,

ob die Variable, in der die Referenz auf das Bitmap-Objekt gehalten wird, readonly ist, sagt in der Tat nichts darüber aus, ob die Zugriffe auf die Bitmap thread-safe sind. Wenn allerdings nur lesend auf ein Objekt zugriffen wird und diese lesenden Operationen auch hinter den Kulissen nichts schreiben/ändern, ist das immer thread-safe, selbst wenn in der Doku steht, dass die Instanz-Member nicht thread-safe sind.

Hallo Konin,

zu den schon angesprochen Pipelines gibt es einen gleichnamigen Artikel auf MSDN: Pipelines.

herbivore

156 Beiträge seit 2010
vor 10 Jahren

Moin,

Ich schreibe momentan an einer PixelBotAPI.

für Tibia? zumindest hatte ich mal da den Gedanken....

Wie hast Du die Bewegung erkannt?1.bild(t-1) - bild(t) => diff1 && bild(t) - bild(t+1) => diff2 1.diff1 U diff2 => menge (bzw. geänderte Bereiche) 1.Segmentierung 1.Templatematching(t-1) & Templatematching(t) => Bewegung

  1. [...Auswertung...]

ich vermute Gaus & Co. hast Du weg gelassen, da die Bilder schon perfekt sind

Bei N logischen Kernen* können wirklich gleichzeitig auch nur N Threads ausgeführt werden.

bei X Threads die immer rechnen würde ich eher auf X ≤ N - 1 gehen, um dem BS und anderen Programmen auch etwas Platz zu gönnen

Ist es möglich mit einem Thread einen bestimmten CPU Kern anzusteuern?
[...]Dabei pfuschst du aber dem Scheduler vom Betriebssystem ins Handwerk und es ergibt sich oft ein eher nachteiliges Ergebnis.

bei der Aufgabe würde ich eher sagen macht es beim Prozessor Sinn. Das Ganze ist eine Mischung aus "wie arbeitet mein Programm" und "wie groß sind L1/L2/L3". Wenn der Cache nicht groß ist um 2 Bilder gleichzeitig vorzuhalten, dann ist es eher Sinnlos den Kern fest zunageln. Da sonst eh der Cache aus dem RAM jedesmal neu gefüllt wird, es also keine Geschwindigkeitsvorteile bringt.

Somit dürfte ein GetPixel - sofern Du das nutzt - nicht Thread-Safe sein.

so lange er nur liest ist das egal - aber - GetPixel ist schrecklich langsam (genau wie SetPixel). Das gesamte Bild muss in Rohdaten vorliegen um halbwegs in Zeit die Bilder verarbeiten zu können. Aber da er ja den Screenshot abgreift, hat OP ja schon ide Rohdaten (außer er hat in der Tat ein BMP draus gemacht).

hand, mogel

im Computer sind physische Kerne verbaut, diese können aber durch Techniken wie Hyperthreading als doppelt soviele logische Kerne verfügbar gemacht werden.

es lebe das Marketing 👅

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo mogel,

so lange er nur liest ist das egal

korrekt, allerdings muss man beachten, dass auch scheinbar nur lesende Operationen intern schreiben können (z.B. Logging, Caching, ...). Und wenn das auf gemeinsame Daten passiert, ist eine aus Aufrufersicht an sich nur lesende Operation trotzdem nicht thread-safe.

herbivore

16.835 Beiträge seit 2008
vor 10 Jahren

Dass GetPixel unheimlich unperformant ist - ich denke, dass das allen hier bewusst ist -> Lockbits.

Nochmal was ich gesagt hab: readonly hat nichts mit Thread-Safe zutun.
Es garantiert absolut nichts. Thread-Safety ist hier vielleicht eine Folgeerscheinung aber keine Garantie.
MSDN: Read-only and threadsafe are different

Wenn GetPixel so implementiert ist, dass kein Handle mehrfach genutzt wird, mag das stimmen; ich kenn den Inhalt nicht. Für BitmapData gilt das gleiche: ich kenns nicht 100%tig.

bei X Threads die immer rechnen würde ich eher auf X ≤ N - 1 gehen, um dem BS und anderen Programmen auch etwas Platz zu gönnen

... und selbst wenn Du einen Kern für einen Thread definierst heisst das noch lange nicht, dass der Kern nicht von einer anderen Anwendung verwendet wird.
Im dümmsten Fall definieren 3 Anwendungen genau den gleichen Kern und 7 andre Kerne haben nichts zutun.
Und wenn es hart auf hart kommt schiebt der Scheduler Deinen Thread ans Ende, weils wichtigere Aufgaben gibt.

Daher hab ich auch die TPL Dokumentation sowie die Pipelines genannt.
Das Konstrukt ist schon ziemlich performant und muss nicht mit ständig neuen Threads und Verschiebungen arbeiten.

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo Abt,


>

in dem Link steht in vielen Worten nichts anderes, als was ich hier in diesem Thread in wenigen gesagt habe. 😃

herbivore