Wie wichtig ist Multithreading in der aktuellen Software-Branche? [geschlossen]


59

Ich habe fast 3 Jahre Erfahrung mit dem Schreiben von Webanwendungen in Java unter Verwendung von MVC-Frameworks (wie Struts). Ich habe bisher noch nie Multithread-Code geschrieben, obwohl ich Code für große Einzelhandelsketten geschrieben habe.

Ich bekomme während eines Interviews ein paar Fragen zum Thema Multithreading und beantworte sie normalerweise (meist einfache Fragen). Ich habe mich deshalb gefragt, wie wichtig Multithreading im aktuellen Branchenszenario ist.


8
Sie haben das vielleicht nicht explizit getan, aber Sie haben es definitiv hinter den Kulissen ausgenutzt.
Martin York

1
Ich arbeite zu selten mit Multithread-Code für die Arbeit, aber ich versuche, mich darüber zu informieren / es während eines Interviews diskutieren zu können. Ich würde nicht mit Codierern arbeiten wollen, die keine Threads bekommen, und ich würde nicht mit Codierern arbeiten wollen, denen es egal ist, ob andere Codierer Threads bekommen.
Job

1
Ich verwende es selten in der Webentwicklung, aber ich denke, dass es anderswo üblicher ist. Zum Beispiel schreibe ich vor kurzem ein Android - App und realisiert sind Sie erforderlich Multithreading verwenden , wenn Sie eine Netzwerkaktivität haben.
Jwegner

4
Es ist nicht das Multithreading, das wichtig ist, sondern das Parallel-Computing. Wenn Sie der Meinung sind, dass jede einzelne Anfrage, die an Ihre Web-App gesendet wird, im Thread ist, müssen Sie etwas rauchen.
user606723

1
Die Fähigkeit, "außerhalb des Threads zu denken", ist selbst für die Single-Thread-Programmierung sehr gut. Sie halten viel weniger für selbstverständlich, und Ihr Code ist im Allgemeinen robuster und wiederverwendbar.
CorsiKa

Antworten:


92

Das ist extrem wichtig.

Wichtiger ist es jedoch zu verstehen, dass Multithreading nur eine Möglichkeit ist, das Asynchronitätsproblem zu lösen. Die technische Umgebung, in der derzeit viele Leute Software schreiben, unterscheidet sich von der historischen Softwareentwicklungsumgebung (von monolithischen Anwendungen, die Stapelberechnungen durchführen) in zweierlei Hinsicht:

  • Many-Core-Maschinen sind mittlerweile weit verbreitet. Es ist nicht mehr zu erwarten, dass Taktraten oder Transistordichten um Größenordnungen zunehmen. Der Preis für Berechnungen wird weiter sinken, er wird jedoch aufgrund vieler Parallelitäten sinken. Wir werden einen Weg finden müssen, diese Kraft auszunutzen.

  • Computer sind heute stark vernetzt, und moderne Anwendungen sind darauf angewiesen, dass sie umfassende Informationen aus einer Vielzahl von Quellen abrufen können.

Aus rechnerischer Sicht laufen diese beiden Faktoren im Wesentlichen auf die gleiche Kernidee hinaus: Informationen werden zunehmend asynchron verfügbar sein . Ob die Informationen, die Sie benötigen, auf einem anderen Chip in Ihrer Maschine oder auf einem Chip in der ganzen Welt berechnet werden, spielt keine Rolle. So oder so sitzt Ihr Prozessor da und verbrennt Milliarden von Zyklen pro Sekunde, um auf Informationen zu warten, wenn er nützliche Arbeit leisten könnte.

Was jetzt zählt und was in Zukunft noch wichtiger sein wird, ist also nicht Multithreading an sich, sondern der Umgang mit Asynchronität . Multithreading ist nur ein Weg, dies zu tun - ein komplizierter, fehleranfälliger Weg, der nur noch komplizierter und fehleranfälliger wird, wenn schwache Speichermodell-Chips immer häufiger eingesetzt werden.

Die Herausforderung für Anbieter von Tools besteht darin, für unsere Kunden eine bessere Lösung als Multithreading zu finden, um mit der künftig verwendeten asynchronen Infrastruktur fertig zu werden.


5
+1 für eine exzellente Antwort, es verdient mehr Anerkennung als mein bescheidener Versuch.
Péter Török,

2
Informationen werden zunehmend asynchron verfügbar sein. Wenn das nicht die Wahrheit ist. . .
Surfasb

2
concurrencyist wichtiger als das asynchronous Verhalten. Sie können asynchrone ohne Parallelität (dh mehrere Threads auf einer einzelnen Kern-CPU) haben, asynchronousist kein semantischer Ersatz für concurrency.

5
@Jarrod: Die Zähmung Asynchronität ist mehr wichtiger als nur die Parallelität Zähmung für genau der Grund , warum Sie erwähnen: Gleichzeitigkeit ist nur eine besonders schwierige Art von Asynchronität. Der schwierige Teil der Nebenläufigkeit ist nicht der Aspekt "Dinge, die zur gleichen Zeit geschehen", und tatsächlich ist die Nebenläufigkeit oft nur eine simulierte Nebenläufigkeit , z. B. nicht kooperatives Multitasking über Time Slicing. Der schwierige Teil besteht darin , Ressourcen effizient zu nutzen, ohne Programme zu blockieren, zu blockieren oder zu blockieren, und ohne Inside-Out- Programme zu schreiben , über die lokal nur schwer nachzudenken ist.
Eric Lippert

"Parallelität ist oft nur simulierte Parallelität, z. B. nicht kooperatives Multitasking über Time Slicing": Nach meinem Verständnis handelt es sich immer noch um (echte) Parallelität, vielleicht meinen Sie, es handelt sich nicht um Parallelität?
Giorgio

46

Es wird immer wichtiger, da moderne Prozessoren immer mehr Kerne haben. Vor einem Jahrzehnt hatten die meisten vorhandenen Computer nur einen einzigen Prozessor, daher war Multithreading nur bei High-End-Serveranwendungen wichtig. Heutzutage haben sogar einfache Laptops Multicore-Prozessoren. In einigen Jahren werden sogar mobile Geräte ... Es wird also immer mehr Code benötigt, um die potenziellen Leistungsvorteile der Parallelität zu nutzen und in einer Multithread-Umgebung ordnungsgemäß ausgeführt zu werden.


3
+1: Wichtiger als je zuvor. Denken Sie auch daran, dass Sie in einem Systemdesign auch die Vorteile von Multithreading nutzen können, indem Sie die Arbeit so partitionieren, dass mehr Prozesse sie ausführen.
Scott C Wilson

11
Nicht wenige mobile Geräte verfügen bereits über Multi-Core-Prozessoren!
Che Jami

3
Ich würde argumentieren, dass Multithreading wichtig war, seit das erste Timesharing-System gebaut wurde. Das Vorhandensein mehrerer Prozessoren / Kerne verleiht dem Vorhandensein mehrerer Threads eine neue Dimension der Effizienz.
jwernerny

Möglicherweise sind Threads (insbesondere auf Mobilgeräten) eine schlechte Idee. Das Betriebssystem sollte wahrscheinlich die Nutzung der Kerne optimieren, ohne dass fehlerhafter Benutzercode versucht, das Threading durchzuführen. Es gibt nur sehr wenige Anwendungen, auf die ein normaler Benutzer Zugriff hat oder die für eine Vielzahl von Benutzern von Vorteil sind. Die einzige Ausnahme bilden (High-End-Grafikanwendungen / Entwicklertools / Wettermodellierung / Webserver (und zugehörige Dienste)) alle sehr High-End-Spezialanwendungen.
Martin York

1
@ Tux-D, möglicherweise haben Sie ein Spiel auf einem mobilen Gerät, das mehr als einen Kern verwendet. Es ist nichts Außergewöhnliches.
Whitequark

28

Im Allgemeinen ist Multithreading bereits sehr wichtig und wird erst in den nächsten Jahren an Bedeutung gewinnen (wie Péter Török betonte) - so werden Prozessoren in absehbarer Zukunft skalieren (mehr Kerne statt höherer MHz) .

In Ihrem Fall scheinen Sie jedoch hauptsächlich mit Webanwendungen zu arbeiten. Aufgrund der Art und Weise, wie Ihr Webserver Anforderungen für jeden Benutzer verarbeitet (dh parallel), sind Webanwendungen von Natur aus multithreaded. Während es für Sie wahrscheinlich wichtig ist, Parallelität und Thread-Sicherheit zu verstehen (insbesondere beim Umgang mit Caches und anderen gemeinsam genutzten Daten), bezweifle ich, dass Sie in zu vielen Fällen den Webanwendungscode intern (dh mit mehreren Workern) in mehrere Threads einbinden können Threads pro Anfrage). In diesem Sinne denke ich, dass es für einen Webentwickler nicht unbedingt notwendig ist, ein Experte für Multithreading zu sein. Es wird oft in Interviews gefragt, weil es ein ziemlich kniffliges Thema ist und weil viele Interviewer nur 10 Minuten vor Ihrer Ankunft ein paar Fragen googeln.


+1 für den Hinweis, dass das Poster ein Webentwickler ist und die meisten Webserver-Container eine angemessene Menge an Multithreading-Arbeit für Sie erledigen. Nicht, dass dies in einigen Fällen die Notwendigkeit beseitigt, aber in 99% der Fälle ist Multithreading-Controller-Code nicht die größte Leistungsverbesserung für einen MVC-Aufruf.
Mufasa

19

Multithreading ist ein roter Hering. Multithreading ist ein Implementierungsdetail für das eigentliche Problem, nämlich die Parallelität . Nicht alle Thread-Programme sind aufgrund von Sperren gleichzeitig aktiv und was nicht.

Threads sind nur ein Modell und ein Implementierungsmuster für die Implementierung von concurrentProgrammen.

Zum Beispiel können Sie hoch skalierbare und fehlertolerante Software schreiben, ohne Multithreading in Sprachen wie Erlang durchführen zu müssen.


+1 obwohl ich immer noch denke, dass Erlang Multi-Threaded ist; Die Community hat das Wort "Faden" so neu definiert, dass es von einem veränderlichen gemeinsamen Zustand abhängt und sich dadurch von diesem unterscheidet.
Dan,

1
Die Erlang-VM verwendet standardmäßig 1 Thread pro CPU. Als Erlang-Entwickler haben Sie jedoch keinen Zugriff auf die zugrunde liegenden Betriebssystem-Threads, sondern nur auf die von der Erlang-VM bereitgestellten Lightweight-Prozesse.

10

Ich bekomme ein paar Fragen zum Thema Multithreading in Interviews ...

Gut, um die Interviews zu bestehen, kann Multithreading sehr wichtig sein. Ich zitiere mich selbst : "Wenn ich Kandidaten für unser Team interviewe, stelle ich nebenläufige Fragen, nicht weil diese Fähigkeiten für unser Projekt wichtig sind (diese sind es nicht ), sondern weil sie es mir irgendwie erleichtern, allgemeine Sprachkenntnisse zu bewerten, die wir verwenden ..."


2
Wenn Sie eine Vorstellung von Multithreading und gleichzeitiger Programmierung haben, bedeutet dies in der Regel auch einen defensiven Ansatz, der sehr hilfreich sein kann. Wenn Sie berücksichtigen müssen, dass etwas, das in Ihrem Prozess völlig unabhängig ist, möglicherweise eine einzelne logische Anweisung verhindert und in der Mitte von allem anderen ausgeführt wird, müssen Sie diese Möglichkeit einplanen. Multithread-Implementierungen (im Gegensatz zu anderen Formen der Parallelität) bedeuten lediglich, dass Sie die zusätzliche Last haben, dass sie möglicherweise etwas mit einem Zustand tun, der nicht thread-lokal ist.
ein Lebenslauf vom

6

In der heutigen Softwareumgebung ist es für die meisten Branchen und Anwendungen von entscheidender Bedeutung, zu verstehen, wie Threading zur Verbesserung der Leistung eingesetzt werden kann.

Zumindest sollte das Verständnis der mit der Parallelität verbundenen Probleme gegeben sein.

Der offensichtliche Hinweis, dass nicht alle Anwendungen oder Umgebungen davon profitieren können, gilt beispielsweise für viele eingebettete Systeme. Es scheint jedoch, als ob der Atom-Prozessor (et al.) Daran arbeitet, dies zu ändern (leichte Multicores werden immer häufiger).


4

Klingt so, als würden Sie bereits Multithread-Code schreiben.

Die meisten Java-Webanwendungen können mehrere Anforderungen gleichzeitig verarbeiten und verwenden dazu mehrere Threads.

Daher würde ich sagen, dass es wichtig ist, zumindest die Grundlagen zu kennen.


18
<nitpick> Anscheinend schreibt er keinen Multithread-Code, sondern nur (Single-Thread-) Code, der in einer Multithread-Umgebung ausgeführt wird. </ nitpick>
Péter Török,

2

Es ist immer noch wichtig in Situationen, in denen Sie es brauchen, aber wie viele andere Dinge in der Entwicklung ist es das richtige Werkzeug für den richtigen Job. Ich war 3 Jahre lang ohne das Einfädeln zu berühren, jetzt hat praktisch alles, was ich tue, einen Grund. Bei Multi-Core-Prozessoren besteht nach wie vor ein großer Bedarf an Threading, aber alle herkömmlichen Gründe sind weiterhin gültig. Sie möchten weiterhin reaktionsschnelle Schnittstellen und möchten weiterhin in der Lage sein, sich mit der Synchronisierung zu befassen und gleichzeitig mit anderen Dingen umzugehen.


2

Kurze Antwort: Sehr.

Längere Antwort: Elektronische (Transistor-basierte) Computer nähern sich schnell den physikalischen Grenzen der Technologie. Es wird immer schwieriger, mehr Takte aus jedem Kern herauszupressen, während die Wärmeerzeugung und die Quanteneffekte mikroskopischer Schaltungen verwaltet werden (Schaltungspfade sind auf modernen Chips bereits so eng beieinander angeordnet, dass ein Effekt namens "Quantentunneling" ein Elektron erzeugen kann "jump the tracks" von einem Stromkreis zum anderen, ohne die richtigen Bedingungen für einen herkömmlichen Lichtbogen zu benötigen); Daher konzentrieren sich praktisch alle Chiphersteller darauf, dass jeder Takt mehr leisten kann, indem mehr "Ausführungseinheiten" in jede CPU eingebaut werden. Anstatt dass der Computer nur eine Aktion pro Uhr ausführt, kann er 2, 4 oder sogar 8 ausführen. Intel hat "HyperThreading", Dies teilt im Grunde einen CPU-Kern in zwei logische Prozessoren auf (mit einigen Einschränkungen). Praktisch alle Hersteller stecken mindestens zwei separate CPU-Kerne in einen CPU-Chip, und der aktuelle Goldstandard für Desktop-CPUs liegt bei vier Kernen pro Chip. Acht sind möglich, wenn zwei CPU-Chips verwendet werden, es gibt Server-Mainboards, die für "Quad-Quad-Core" -Prozessoren (16 EUs plus optionales HT) ausgelegt sind, und die nächste Generation von CPUs wird wahrscheinlich sechs oder acht pro Chip haben.

Das Ergebnis all dessen ist, dass Sie es dem Computer ermöglichen müssen, Ihr Programm zu "teilen und zu erobern", damit er die Vorteile der Computer nutzen kann, die an Rechenleistung zunehmen. Verwaltete Sprachen haben mindestens einen GC-Thread, der die Speicherverwaltung separat von Ihrem Programm verwaltet. Einige haben auch "Transition" -Threads, die COM / OLE-Interop verarbeiten (sowohl für den Schutz der verwalteten "Sandbox" als auch für die Leistung). Darüber hinaus müssen Sie jedoch überlegen, wie Ihr Programm mehrere Aufgaben gleichzeitig ausführen kann, und Ihr Programm mit Funktionen versehen, mit denen Teile des Programms asynchron verarbeitet werden können. Windows und Windows-Benutzer erwarten praktisch, dass Ihr Programm lange, komplizierte Aufgaben in Hintergrundthreads ausführt. Die Benutzeroberfläche Ihres Programms (das im Hauptthread des Programms ausgeführt wird) reagiert auf die Windows-Nachrichtenschleife. Natürlich sind Probleme mit parallelisierbaren Lösungen (wie das Sortieren) natürliche Kandidaten, aber es gibt eine begrenzte Anzahl von Problemtypen, die von der Parallelisierung profitieren.


1

Nur eine Warnung zum Multithreading: Mehr Threads bedeuten keine bessere Effizienz. Wenn sie nicht ordnungsgemäß verwaltet werden, können sie das System verlangsamen. Scalas Schauspieler verbessern Javas Threading und maximieren die Systemnutzung (erwähnt als Java-Entwickler).

EDIT: Hier sind einige Dinge zu beachten, die die Nachteile von Multithreading betreffen:

  • Interferenz von Threads untereinander beim Teilen von Hardwareressourcen
  • Die Ausführungszeiten eines einzelnen Threads werden nicht verbessert, können jedoch beeinträchtigt werden, selbst wenn nur ein Thread ausgeführt wird. Dies ist auf langsamere Frequenzen und / oder zusätzliche Pipeline-Stufen zurückzuführen, die zur Aufnahme von Thread-Switching-Hardware erforderlich sind.
  • Die Hardwareunterstützung für Multithreading ist für die Software sichtbarer und erfordert daher mehr Änderungen an Anwendungsprogrammen und Betriebssystemen als Multiprocessing.
  • Schwierigkeiten beim Verwalten der Parallelität.
  • Schwierigkeiten beim Testen.

Auch diese Verbindung könnte eine Hilfe in etwa gleich sein.


2
Dies scheint die Frage des OP nicht zu beantworten: - /
Péter Török

Es gibt jedoch eine Top-Level-Ansicht des Threadings. Was Sie beachten müssen, bevor Sie sich mit Multithreading befassen.
c0da

@ c0da Stack Exchange ist kein Diskussionsforum: Antworten sollten die Frage direkt beantworten. Können Sie Ihre Antwort erweitern, um sie auf das zurückzubringen, wonach der Fragesteller sucht?

1

Ich habe mich deshalb gefragt, wie wichtig Multithreading im aktuellen Branchenszenario ist.

In leistungskritischen Bereichen, in denen die Leistung nicht von Drittanbieter-Code stammt, sondern von unserem eigenen Code, würde ich Dinge aus der CPU-Perspektive eher in dieser Reihenfolge berücksichtigen (die GPU ist ein Platzhalter, den ich gewonnen habe) geht nicht rein):

  1. Speichereffizienz (zB Referenzort).
  2. Algorithmisch
  3. Multithreading
  4. SIMD
  5. Sonstige Optimierungen (statische Verzweigungsvorhersage-Hinweise, zB)

Beachten Sie, dass diese Liste nicht nur von der Wichtigkeit abhängt, sondern auch von vielen anderen Faktoren wie den Auswirkungen auf die Wartung, wie einfach sie sind (wenn nicht, sollten Sie dies im Voraus berücksichtigen), ihren Interaktionen mit anderen auf der Liste usw.

Speichereffizienz

Die meisten sind vielleicht überrascht, dass ich die Speichereffizienz gegenüber der algorithmischen Wahl gewählt habe. Dies liegt daran, dass die Speichereffizienz mit allen vier anderen Elementen in dieser Liste interagiert und die Berücksichtigung häufig eher in der Kategorie "Design" als in der Kategorie "Implementierung" erfolgt. Zugegebenermaßen gibt es hier ein kleines Problem mit Hühnern oder Eiern, da für das Verständnis der Speichereffizienz häufig alle 4 Elemente auf der Liste berücksichtigt werden müssen, während für alle 4 anderen Elemente auch die Speichereffizienz berücksichtigt werden muss. Dennoch ist es das Herzstück von allem.

Wenn wir beispielsweise eine Datenstruktur benötigen, die sequentiellen Zugriff in linearer Zeit und zeitlich konstante Einfügungen nach hinten und nichts anderes für kleine Elemente bietet, wäre die naive Wahl, nach der wir hier greifen, eine verknüpfte Liste. Das ignoriert die Speichereffizienz. Wenn wir die Speichereffizienz in der Mischung berücksichtigen, wählen wir in diesem Szenario am Ende zusammenhängendere Strukturen aus, wie z. B. anwachsende Array-basierte Strukturen oder zusammenhängende Knoten (z. B. einer, der 128 Elemente in einem Knoten speichert), die miteinander verbunden sind, oder zumindest eine verknüpfte Liste, die von einem Pool-Allokator unterstützt wird. Diese haben trotz der gleichen algorithmischen Komplexität einen dramatischen Vorteil. Ebenso wählen wir häufig die schnelle Sortierung eines Arrays anstelle der Sortierung nach Zusammenführung, obwohl die algorithmische Komplexität aufgrund der Speichereffizienz minderwertig ist.

Ebenso können wir kein effizientes Multithreading haben, wenn unsere Speicherzugriffsmuster so detailliert und verstreut sind, dass wir das Ausmaß der falschen Freigabe maximieren und gleichzeitig auf den detailliertesten Codeebenen sperren. Die Speichereffizienz multipliziert also die Effizienz von Multithreading. Dies ist eine Grundvoraussetzung, um das Beste aus den Threads herauszuholen.

Jedes einzelne Element in der Liste hat eine komplexe Interaktion mit Daten, und die Konzentration auf die Darstellung von Daten trägt letztendlich zur Speichereffizienz bei. Jedes einzelne dieser oben genannten Elemente kann mit einer unangemessenen Art der Darstellung oder des Zugriffs auf Daten in Konflikt geraten.

Ein weiterer Grund, warum die Speichereffizienz so wichtig ist, besteht darin, dass sie auf die gesamte Codebasis angewendet werden kann . Im Allgemeinen ist es ein Zeichen dafür, dass man sich einen Profiler zulegen muss, wenn man sich vorstellt, dass sich Ineffizienzen durch kleine Teile der Arbeit hier und da ansammeln. Felder mit geringer Latenz oder solche, die sich mit sehr begrenzter Hardware befassen, werden auch nach der Profilerstellung tatsächlich Sitzungen finden, die keine eindeutigen Hotspots (nur zeitweise über den gesamten Bereich verteilt) in einer Codebasis anzeigen, die bei der Zuweisung, beim Kopieren und bei der Erstellung von Profilen eklatant ineffizient ist Zugriff auf Speicher. In der Regel ist dies das einzige Mal, dass eine gesamte Codebasis Leistungsproblemen ausgesetzt ist, die zu einer Reihe neuer Standards führen können, die in der gesamten Codebasis angewendet werden, und die Speichereffizienz steht häufig im Mittelpunkt.

Algorithmisch

Dies ist so ziemlich selbstverständlich, da die Auswahl in einem Sortieralgorithmus den Unterschied zwischen einer massiven Eingabe, deren Sortierung Monate in Anspruch nimmt, und Sekunden in Anspruch nimmt. Es macht den größten Einfluss von allen, wenn die Wahl zwischen beispielsweise wirklich unterdurchschnittlichen quadratischen oder kubischen Algorithmen und einem linearen oder zwischen linearen und logarithmischen oder konstanten Algorithmus besteht, zumindest bis wir 1.000.000 Kernmaschinen haben (in diesem Fall Speicher) Effizienz würde noch wichtiger werden).

Es steht jedoch nicht ganz oben auf meiner persönlichen Liste, da jeder, der auf seinem Gebiet kompetent ist, wissen würde, wie man eine Beschleunigungsstruktur für das Abtöten von Kegelstümpfen verwendet Ein Radix-Baum für Präfix-basierte Suchanfragen ist Babymaterial. Ohne diese Grundkenntnisse in dem Bereich, in dem wir arbeiten, würde die algorithmische Effizienz sicherlich an die Spitze rücken, aber die algorithmische Effizienz ist oftmals trivial.

Auch das Erfinden neuer Algorithmen kann in einigen Bereichen eine Notwendigkeit sein (z. B. bei der Netzverarbeitung musste ich Hunderte erfinden, da sie entweder vorher nicht existierten oder die Implementierung ähnlicher Funktionen in anderen Produkten proprietäre Geheimnisse waren, die nicht in einem Papier veröffentlicht wurden ). Sobald wir jedoch den Teil zur Problemlösung hinter uns haben und einen Weg finden, die richtigen Ergebnisse zu erzielen, und wenn Effizienz zum Ziel wird, können wir nur noch darüber nachdenken, wie wir mit Daten (Speicher) interagieren. Ohne die Speichereffizienz zu verstehen, kann der neue Algorithmus mit vergeblichen Anstrengungen, ihn zu beschleunigen, unnötig komplex werden, wenn nur die Speichereffizienz berücksichtigt werden muss, um einen einfacheren und eleganteren Algorithmus zu erhalten.

Schließlich liegen Algorithmen eher in der Kategorie "Implementierung" als in der Kategorie "Speichereffizienz". Sie sind im Nachhinein oft einfacher zu verbessern, selbst wenn zunächst ein suboptimaler Algorithmus verwendet wird. Beispielsweise wird ein schlechterer Bildverarbeitungsalgorithmus oft nur an einer lokalen Stelle in der Codebasis implementiert. Es kann später gegen ein besseres ausgetauscht werden. Wenn jedoch alle Bildverarbeitungsalgorithmen an eine PixelSchnittstelle gebunden sind, die eine suboptimale Speicherdarstellung aufweist, aber die einzige Möglichkeit zur Korrektur darin besteht, die Darstellung mehrerer Pixel (und nicht eines einzigen) zu ändern, sind wir häufig SOL und müssen die Codebasis in Richtung eines vollständig umschreibenImageSchnittstelle. Das Gleiche gilt für das Ersetzen eines Sortieralgorithmus - normalerweise handelt es sich um ein Implementierungsdetail, während eine vollständige Änderung der zugrunde liegenden Darstellung der zu sortierenden Daten oder der Art und Weise, wie sie durch Nachrichten geleitet werden, möglicherweise eine Neugestaltung der Schnittstellen erforderlich macht.

Multithreading

Multithreading ist eine schwierige Aufgabe im Hinblick auf die Leistung, da es sich um eine Optimierung auf Mikroebene handelt, die auf Hardwareeigenschaften abzielt, aber unsere Hardware skaliert tatsächlich in diese Richtung. Bereits habe ich Gleichaltrige, die 32 Kerne haben (ich habe nur 4).

Mulithreading gehört jedoch zu den gefährlichsten Mikrooptimierungen, die einem Fachmann wahrscheinlich bekannt sind, wenn der Zweck darin besteht, Software zu beschleunigen. Die Racebedingung ist so ziemlich der tödlichste Fehler, der möglich ist, da sie so unbestimmt ist (möglicherweise wird sie nur einmal alle paar Monate auf dem Computer eines Entwicklers zu einem äußerst ungünstigen Zeitpunkt außerhalb eines Debugging-Kontexts angezeigt, wenn überhaupt). Es hat also die wohl negativste Beeinträchtigung der Wartbarkeit und potenziellen Korrektheit von Code unter all diesen, zumal Fehler im Zusammenhang mit Multithreading selbst bei sorgfältigsten Tests leicht zu übersehen sind.

Trotzdem wird es so wichtig. Auch wenn es angesichts der Anzahl der Kerne, die wir jetzt haben, nicht immer besser ist als die Speichereffizienz (die manchmal die Dinge hundertmal schneller macht), sehen wir immer mehr Kerne. Selbst bei Computern mit 100 Kernen würde ich die Speichereffizienz immer noch ganz oben auf die Liste setzen, da die Thread-Effizienz ohne sie im Allgemeinen nicht möglich ist. Ein Programm kann auf einer solchen Maschine hundert Threads verwenden und trotzdem langsam sein, ohne effiziente Speicherdarstellung und Zugriffsmuster (die mit Sperrmustern verknüpft sind).

SIMD

SIMD ist auch ein bisschen umständlich, da die Register tatsächlich breiter werden, mit Plänen, noch breiter zu werden. Ursprünglich sahen wir 64-Bit-MMX-Register, gefolgt von 128-Bit-XMM-Registern, die 4 SPFP-Operationen parallel ausführen können. Jetzt sehen wir 256-Bit-YMM-Register, die 8 parallel ausführen können. Und es gibt bereits Pläne für 512-Bit-Register, die 16 parallel zulassen würden.

Diese würden mit der Effizienz von Multithreading interagieren und sich vervielfachen. SIMD kann jedoch die Wartbarkeit genauso beeinträchtigen wie Multithreading. Auch wenn Fehler, die mit ihnen zusammenhängen, nicht unbedingt so schwer zu reproduzieren und zu beheben sind wie ein Deadlock oder eine Race-Bedingung, ist die Portabilität umständlich und es muss sichergestellt werden, dass der Code auf jedem Computer ausgeführt werden kann (und die entsprechenden Anweisungen basierend auf den Hardware-Funktionen verwendet werden) peinlich.

Eine andere Sache ist, dass Compiler heutzutage normalerweise keinen fachmännisch geschriebenen SIMD-Code schlagen, aber naive Versuche leicht bestehen. Sie werden möglicherweise so weit verbessert, dass wir sie nicht mehr manuell ausführen müssen oder zumindest nicht mehr so ​​manuell, dass sie inhärenten Code oder reinen Assembler-Code schreiben (vielleicht nur eine kleine menschliche Anleitung).

Auch hier ist SIMD ohne ein für die vektorisierte Verarbeitung effizientes Speicherlayout nutzlos. Am Ende wird nur ein Skalarfeld in ein breites Register geladen, um nur eine Operation auszuführen. Das Herzstück all dieser Elemente ist die Abhängigkeit von Speicherlayouts, um wirklich effizient zu sein.

Andere Optimierungen

Ich würde oft vorschlagen, dass wir heutzutage von "Mikro" sprechen, wenn das Wort andeutet, dass nicht nur der algorithmische Fokus überschritten wird, sondern auch Änderungen, die sich nur geringfügig auf die Leistung auswirken.

Häufig erfordert der Versuch, die Verzweigungsvorhersage zu optimieren, eine Änderung des Algorithmus oder der Speichereffizienz. Wenn dies z. B. nur durch Hinweise versucht wird und der Code für die statische Vorhersage neu angeordnet wird, wird die erstmalige Ausführung dieses Codes tendenziell nur verbessert, was die Auswirkungen in Frage stellt, wenn nicht oft völlig zu vernachlässigen.

Zurück zu Multithreading für Leistung

Wie wichtig ist Multithreading in einem Leistungskontext? Auf meinem 4-Core-Rechner können die Dinge idealerweise etwa fünfmal schneller gemacht werden (was ich mit Hyperthreading erreichen kann). Für meinen Kollegen mit 32 Kernen wäre das wesentlich wichtiger. Und es wird in den kommenden Jahren immer wichtiger.

Also ist es ziemlich wichtig. Es ist jedoch sinnlos, nur eine Reihe von Threads auf das Problem zu werfen, wenn die Speichereffizienz nicht ausreicht, um die sparsame Verwendung von Sperren zu ermöglichen, falsche Freigabe zu reduzieren usw.

Multithreading außerhalb der Leistung

Beim Multithreading geht es nicht immer nur um reine Leistung im Sinne eines einfachen Durchsatzes. Manchmal wird es verwendet, um eine Last sogar auf die möglichen Kosten des Durchsatzes auszugleichen, um die Reaktionsfähigkeit des Benutzers zu verbessern, oder um es dem Benutzer zu ermöglichen, mehr Multitasking auszuführen, ohne darauf zu warten, dass die Dinge abgeschlossen sind (z. B. Fortsetzen des Surfens beim Herunterladen einer Datei).

In diesen Fällen würde ich vorschlagen, dass Multithreading nach oben hin noch weiter ansteigt (möglicherweise sogar über die Speichereffizienz hinaus), da es dann eher um benutzerorientiertes Design geht, als darum, das Beste aus der Hardware herauszuholen. Es wird häufig das Interface-Design und die Art und Weise dominieren, wie wir unsere gesamte Codebasis in solchen Szenarien strukturieren.

Wenn wir nicht einfach eine enge Schleife parallelisieren, die auf eine massive Datenstruktur zugreift, wird Multithreading in die Kategorie "Design" eingestuft, und Design ist immer wichtiger als die Implementierung.

In diesen Fällen würde ich sagen, dass Multithreading im Vorfeld von entscheidender Bedeutung ist, noch mehr als die Speicherdarstellung und der Speicherzugriff.


0

Gleichzeitige und parallele Programmierung wird immer wichtiger. Threads sind nur ein Programmiermodell, um mehrere Dinge gleichzeitig zu erledigen (und nicht pseudo-parallel, wie es früher vor dem Aufkommen von Mehrkernprozessoren der Fall war). Multithreading wird (meiner Meinung nach) als komplex und gefährlich kritisiert, da Threads viele Ressourcen gemeinsam nutzen und der Programmierer dafür verantwortlich ist, dass sie zusammenarbeiten. Andernfalls kommt es zu Deadlocks, die nur schwer zu debuggen sind.


0

Da wir möglicherweise viele externe Anwendungen kontaktieren müssen, kann ein Hintergrundprozess auftreten, bei dem die Interaktion mit dem externen System länger dauert und der Endbenutzer nicht warten kann, bis der Prozess abgeschlossen ist. Multithreading ist also wichtig ..

Wir verwenden in unserer App zunächst das externe System. Wenn es nicht funktioniert, speichern wir die Anforderung in der Datenbank und spannen einen Thread auf, um den Vorgang in backgound abzuschließen. Kann auch in Batch-Operationen erforderlich sein.


0

In der Vergangenheit hatten die Menschen Probleme damit, Multithread-Programme von Hand zu erstellen. Sie mussten direkt mit allen Kernkomponenten (Threads, Semaphoren, Mutexe, Sperren usw.) arbeiten.

All diese Bemühungen führten zu Anwendungen, die durch Hinzufügen von zusätzlichem CPU zu einem einzelnen System skaliert werden konnten. Diese vertikale Skalierbarkeit ist begrenzt durch "Was ist der größte Server, den ich kaufen kann".

Heutzutage sehe ich eine Verlagerung hin zur Verwendung von mehr Frameworks und verschiedenen Designmodellen für das Software-Design. MapReduce ist ein solches Modell, das sich auf die Stapelverarbeitung konzentriert.

Das Ziel ist die horizontale Skalierung. Hinzufügen von mehr Standardservern, anstatt größere Server zu kaufen.

Trotzdem bleibt die Tatsache, dass es sehr wichtig ist, Multithread-Programme wirklich zu verstehen. Ich war in einer Situation, in der jemand eine Rennbedingung erstellt hat und wusste nicht einmal, was eine Rennbedingung ist, bis wir beim Testen merkwürdige Fehler bemerkten.


-1

Meine Maschine hat 8 Kerne. Im Task-Manager werden 60 Prozesse ausgeführt. Einige, wie VS, verwenden bis zu 98 Threads. Outlook verwendet 26. Ich gehe davon aus, dass der größte Teil meines Arbeitsspeichers aus den Stapeln besteht, die jedem dieser inaktiven Threads zugewiesen sind.

Ich persönlich warte darauf, dass der 300-Core-Computer herauskommt, damit ich nicht warten muss, bis Outlook antwortet. Natürlich wird Outlook bis dahin 301 Threads verwenden.

Multithreading ist nur dann von Bedeutung, wenn Sie Systeme erstellen, die zu einem bestimmten Zeitpunkt der einzige wichtige Prozess auf dem Computer sind (z. B. Berechnungsmodule). Desktop-Apps würden dem Benutzer wahrscheinlich einen Gefallen tun, indem sie nicht jeden verfügbaren Kern verbrauchen. Web-Apps, die das Anforderungs- / Antwortmodell verwenden, sind von Natur aus multithreaded.

Es ist wichtig für Framework- und Sprachentwickler sowie für Back-End-Systemprogrammierer - weniger für Anwendungsentwickler. Es lohnt sich jedoch wahrscheinlich, einige grundlegende Konzepte wie das Sperren und Schreiben von asynchronem Code zu verstehen.


Ich werde oft etwas auf einen Hintergrund-Thread wie eine lange DB-Last schlagen, aber es ist sehr selten, dass ich mich mit Rennbedingungen oder Sperren usw. auseinandersetzen muss (tatsächlich wahrscheinlich nie)
Aran Mulholland,
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.