Informatik: EINFÜHRUNG in MULTI-THREADING (Golang) | Scott Reese | Skillshare

Playback-Geschwindigkeit


1.0x


  • 0.5x
  • 0.75x
  • 1x (normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

Informatik: EINFÜHRUNG in MULTI-THREADING (Golang)

teacher avatar Scott Reese, Engineer & Investor

Schau dir diesen Kurs und Tausende anderer Kurse an

Erhalte unbegrenzten Zugang zu allen Kursen
Lerne von Branchenführern, Ikonen und erfahrenen Experten
Wähle aus einer Vielzahl von Themen, wie Illustration, Design, Fotografie, Animation und mehr

Schau dir diesen Kurs und Tausende anderer Kurse an

Erhalte unbegrenzten Zugang zu allen Kursen
Lerne von Branchenführern, Ikonen und erfahrenen Experten
Wähle aus einer Vielzahl von Themen, wie Illustration, Design, Fotografie, Animation und mehr

Einheiten dieses Kurses

    • 1.

      Einführung

      1:07

    • 2.

      Prozesse und Fäden

      10:48

    • 3.

      Grundlegende Thread

      19:05

    • 4.

      Threadpool erstellen

      16:22

    • 5.

      Wir kommen zum Ende.

      0:43

  • --
  • Anfänger-Niveau
  • Fortgeschrittenes Niveau
  • Fortgeschrittenes Niveau
  • Jedes Niveau

Von der Community generiert

Das Niveau wird anhand der mehrheitlichen Meinung der Teilnehmer:innen bestimmt, die diesen Kurs bewertet haben. Bis das Feedback von mindestens 5 Teilnehmer:innen eingegangen ist, wird die Empfehlung der Kursleiter:innen angezeigt.

203

Teilnehmer:innen

1

Projekte

Über diesen Kurs

Multithreading ist ein sehr wichtiges Konzept in der Welt des software Es ermöglicht es dem Programmierer, Anwendungen zu schreiben, die Multitasking (mehrere Dinge gleichzeitig machen), die dazu dienen, signifikante Verbesserungen in Geschwindigkeit und Effizienz zu bieten!

Dieser Kurs gibt dir eine großartige Einführung in das Konzept des multithreading und führt dich durch einige konkrete Beispiele mit Golang und veranschaulicht wie Fäden funktionieren. Darüber hinaus lernst du auch, wie du einen threadpool, erstellen kannst, der ein sehr beliebtes threading ist, das in Multithread-Anwendungen oft verwendet wird!

Triff deine:n Kursleiter:in

Teacher Profile Image

Scott Reese

Engineer & Investor

Kursleiter:in
Level: Beginner

Kursbewertung

Erwartungen erfüllt?
    Voll und ganz!
  • 0%
  • Ja
  • 0%
  • Teils teils
  • 0%
  • Eher nicht
  • 0%

Warum lohnt sich eine Mitgliedschaft bei Skillshare?

Nimm an prämierten Skillshare Original-Kursen teil

Jeder Kurs setzt sich aus kurzen Einheiten und praktischen Übungsprojekten zusammen

Mit deiner Mitgliedschaft unterstützt du die Kursleiter:innen auf Skillshare

Lerne von überall aus

Ob auf dem Weg zur Arbeit, zur Uni oder im Flieger - streame oder lade Kurse herunter mit der Skillshare-App und lerne, wo auch immer du möchtest.

Transkripte

1. Einführung: Hey da und willkommen in meiner Klasse über eine Einführung in Multi-Threading, die ein sehr, sehr wichtiges Konzept in der Welt der Software Engineering ist. Denn wenn Sie dieses Konzept richtig in Ihre eigene Programmierung anwenden können, wird es die Geschwindigkeit und Effizienz Ihrer Anwendungen drastisch verbessern. Und darüber hinaus, wenn Sie ein festes Verständnis für Multi-Threading haben und seine Anwendungsfälle in einem Interview demonstrieren können , das Ihnen wirklich helfen wird, sich hervorzuheben und Ihnen eine viel höhere Chance geben, einen Software-Engineering-Job zu landen. Und so wurde diese Klasse entwickelt, um Ihnen eine sehr gute Einführung in das Konzept des Multithreading zu geben. Also werden wir beginnen, indem wir über die wichtigsten Konzepte sprechen, die Sie verstehen müssen, bevor Sie tatsächlich anfangen können, Code zu schreiben. Und danach werde ich Ihnen einige sehr klare Beispiele zeigen, indem ich das Ziel verwende, wie Threads funktionieren. Und dann am Ende des Kurses werden wir einen Thread-Pool erstellen. Und wenn du nicht weißt, was das ist, dann schau dir diesen Kurs an und du wirst herausfinden, er sehr, sehr cool ist. Und auch wenn dies der erste Kurs von mir gekommen ist, mein Name ist Scott Reese und ich arbeite derzeit als Software-Ingenieur in der Finanzdienstleistungsbranche. Und ich habe auch einen Abschluss in Wirtschaftswissenschaften und Informatik von der UC Berkeley. Mit dem gesagt, werden Sie in diesem Kurs definitiv in sehr guten Händen sein. Und jetzt springen wir zu meinem Computer und wir werden die Dinge loslegen. 2. Prozesse und Threads: Okay, willkommen zum ersten Video in diesem Kurs über eine Einführung in Multi-Threading, das im Wesentlichen nur Multitasking für Computer ist. Wenn Sie also Multithreading nicht in Ihre Programme einführen können, wird dies Ihnen eine dramatische Beschleunigung Ihrer Programmausführung geben. Und es wird in all die schmutzigen Details darüber eingehen wie dieses Zeug in diesem Kurs funktioniert. Und so möchte ich in diesem ersten Video nur ein paar Hauptthemen auf hoher Ebene abdecken, speziell in dieser Folie. Zunächst möchte ich darüber sprechen, was ein Prozess ist, insbesondere ein Prozess in Bezug auf Computerprogrammierung. Und so ist ein Prozess einfach ein Computerprogramm, das in der Ausführung ist. Also, wenn Sie Ihren eigenen Code ausführen oder wenn Sie einfach ein Programm auf Ihrem Computer öffnen , das bereits wie Microsoft Word, Google Chrome, et cetera installiert ist. Die Ausführung dieses Programms wird als Prozess verpackt werden. Und jeder Prozess, der auf Ihrem Computer läuft, hat seinen eigenen Adressraum im Speicher oder RAM, richtig? Zum Beispiel hat der Computer, auf dem ich dieses Video aufnehme, 16 Gigabyte RAM. Und diese 16 Gigabyte werden in einzelne Speicherblöcke unterteilt, wobei jeder Block einem bestimmten Prozess oder einem bestimmten Programm entspricht , das auf meinem Computer ausgeführt wird. Und jeder Speicherblock für jeden einzelnen Prozess auf Ihrem Computer ist selbst in vier Hauptkomponenten unterteilt. Wir haben den Stapel, den Heap, die Daten oder statischen Abschnitt und den Text- oder Codeabschnitt. Und hier ist ein Diagramm, mit dem Sie visualisieren können, wie das funktioniert. Und tatsächlich lassen Sie mich wieder aus diesem PowerPoint ganz schnell hier, damit Sie meinen Cursor sehen können. So können Sie diesen gesamten Block direkt hier visualisieren, dieses Rechteck als Adressraum, der für einen einzelnen Prozess bestimmt ist. Und dieser Adressraum oder dieser Block des Speichers, ist in die vier Hauptsegmente unterteilt. Der Stapel, der Heap, der Daten oder der statische Abschnitt und der Textschrägstrich. Und beginnend mit dem Stapel zuerst, was ist das? Der Stack enthält im Grunde temporäre Daten wie Funktionsparameter, Variablen innerhalb von Funktionen, Rückgabewerte, et cetera. Grundsätzlich, wenn Sie eine Funktion in Ihrem Code aufrufen, alle Parameter, die an diese Funktion übergeben wurden, und alle Variablen innerhalb dieser Funktion, die verwendet werden, um jede Berechnung durchzuführen. All das wird im Stapelbereich gespeichert. Und Sie können diesen Pfeil hier sehen, was bedeutet, dass der Stapel tatsächlich herunterwachsen wird. Es wird größer, wenn Ihr Programm ausgeführt wird, oder? Denn wenn Sie darüber nachdenken, wenn Ihr Programm zum ersten Mal startet, wird es eine Funktion aufrufen. Und wie ich schon sagte, das wird hier einiges auf den Stapelraum legen. Und dann, wenn diese Funktion ausgeführt wird, könnte eine andere Funktion aufrufen. Und wenn diese zweite Funktion aufgerufen wird, muss sie ihre Parameter und ihre Variablen auch dem Stack-Raum zuweisen. Und dann sehr ähnlich, könnte diese zweite Funktion, wie sie ausgeführt wird, eine dritte Funktion aufrufen und so weiter und so weiter. Es ist, wie ich sagte, da Ihr Programm ausgeführt wird und immer mehr Funktionen aufgerufen werden, wird der Stack-Raum an Größe wachsen. Jetzt schließlich, wenn Ihre Funktionen ausgeführt werden und sie zurückkehren, nun an diesem Punkt, werden Sie nicht mehr die Parameter und Variablen benötigen , die auf dem Stapelspeicher gespeichert wurden, so dass sie entfernt werden. So letztendlich, wenn Ihr Programm ausgeführt wird, wird der Stapelspeicher auf dem Weg wachsen und schrumpfen. Jetzt ist der Heap-Speicherplatz für dynamisch zugewiesenen Speicher. Also im Grunde für jedes Objekt oder für jede Variable, bei der Sie die Größe nicht im Voraus kennen können , bevor der Code tatsächlich ausgeführt wird. Wir werden während der tatsächlichen Ausführung des Codes, wenn diese Variable oder das Objekt instanziiert wird, der für dieses Objekt verwendete Speicher im Heap-Raum zugewiesen werden. Jetzt können die Dinge etwas verwirrend werden, wenn es darum geht den Unterschied zwischen einem Stapel und dem Heap zu verstehen, richtig? Denn abhängig vom Datentyp bestimmter Variablen wird diese Variable manchmal im Stapelbereich gespeichert, in dem sie in den Heap gehen könnte. Und tatsächlich zu verstehen, wie all das funktioniert, ist für diesen Kurs nicht erforderlich. Also werde ich hier nicht zu viel Zeit damit verbringen, aber nur im Allgemeinen, wenn Sie eine Funktion hatten und dann in dieser Funktion eine Variable erstellt haben , die gerade in Integer gespeichert ist. Nun, in diesem Fall wissen wir im Voraus, bevor der Code ausführt, wie viel Speicher benötigt wird, um diesen ganzzahligen Variablenwert zu halten und 32 Bit sein könnte, es könnte 64 Bit sein, hängt nur vom genauen Datentyp ab, den Sie verwenden. Aber etwas sehr Einfaches wie das würde im Stapelbereich gespeichert werden. Und dann, wenn Sie auch in dieser Funktion eine andere Variable hatten , die ein Datenstrukturobjekt speichert, vielleicht eine LinkedList, vielleicht eine HashMap oder so etwas, wo die Größe dieses Objekts und tatsächlich wächst und schrumpfen. Es ist nicht im Voraus bekannt, dann wird der Speicher, der für diese Variable für dieses Objekt verwendet wird dynamisch im Heap-Raum zugewiesen, wenn der Code tatsächlich ausgeführt wird. So sehr ähnlich dem Stack-Raum, wird der Heap-Raum auch wachsen und verkleinern sowie Ihr Code wird ausgeführt und Sie erstellen mehr Objekte oder entfernen mehr Objekte, der gesamte Speicher, der für diese Objekte zugewiesen wird auch im Heap-Raum wachsen und schrumpfen. Als nächstes haben wir den Daten- oder statischen Abschnitt, und das ist einfach, wo Ihre globalen Variablen oder Ihre statischen Variablen gehen. Wenn Sie also Konstanten oder Variablen haben , die außerhalb des Bereichs einer Funktion definiert sind, was sie daher global macht, werden sie in den Datenabschnitt des Adressraums gehen , der für Ihren gesamten Prozess. Und schließlich haben wir den Text- oder Code-Abschnitt. Und das speichert im Grunde nur die eigentlichen Anweisungen, um Ihren Code auszuführen. Grundsätzlich, sobald Ihr Code kompiliert und in Computercode oder in Binärdatei konvertiert wird, werden diese binären Anweisungen im Textbereich Ihres Prozessadressraums gespeichert . Also zusammenfassend hier, sobald Sie einen Prozess auf Ihrem Computer starten, und dieser Prozess wird in Ihren Speicher oder in Ihren RAM geladen. Ihr Computer sucht den Text- oder Codeabschnitt dieses Prozesses , um mit der Ausführung der eigentlichen Anweisungen Ihres Programms zu beginnen. Und wenn diese Anweisungen ausgeführt werden, wächst und schrumpft der Stapelspeicher basierend auf den Parametern und Variablen, die von Ihren Funktionen in Ihrem Code verwendet werden. Und nebenbei wird auch der Haufenraum wachsen und schrumpfen. Und wenn Ihr Code auch die Verwendung globaler Konstanten oder Variablen erfordert, greifen sie einfach auf diese im Datenabschnitt direkt hier zu. Und das war's. Das ist es, was ein Prozess ist. Und das ist in der Regel auf einem hohen Niveau, wie alles funktioniert. Also komm jetzt zur nächsten Folie hier. Und wir werden diskutieren, was ein Faden ist. Und ein Thread ist einfach ein einziger Ausführungsfluss durch Ihren Prozesscode. Also im Grunde der Code, den Sie in Ihrem Prozess ausführen, in Ihrem Programm ist ein Thread eine einzige Ausführung dieses Codes. Und mit dieser Definition impliziere ich im Grunde auch, dass Sie mehrere Ausführungen desselben Codes haben können. Und so behält jeder Thread seinen eigenen Programmzähler und Stack- oder Stack-Platz innerhalb des Prozesses. Jeder Thread ist also seine eigene isolierte Ausführung Ihres Programmcodes. Und jeder Thread kann verschiedene Teile dieses Codes gleichzeitig ausführen. Nun, außerhalb des Stapelspeichers, außerhalb der eigenen Ausführung Ihres Codes, teilen Threads den gesamten anderen Speicher im Prozess. Sie zeigen den Heap, sie zeigen die Daten oder den statischen Abschnitt und sie teilen auch den Text- oder Codeabschnitt. Und Threads sind viel leichter als ein vollwertiger Prozess, was im Grunde bedeutet, dass es viel mehr Overhead gibt und es viel länger dauert, einen vollständigen Prozess zu starten als nur ein einzelner Thread. Es ist sehr schnell und einfach, Threads zu starten und zu stoppen , um sie auf der CPU auszutauschen, et cetera. Und das ist einer der Gründe, warum Multithreading oder die Verwendung mehrerer Threads in Ihrem Prozess so ein sehr leistungsfähiges Werkzeug ist. Und so ist der Zweck, Threads in Ihrem Programm oder in Ihrem Prozess zu verwenden , um Code gleichzeitig auszuführen, richtig? Sie können mehrere Kopien Ihres Codes gleichzeitig ausführen oder andere Threads ersetzen, die derzeit blockiert sind. Und was ich damit meine, ist sagen wir, ein Thread, da er Ihren Code ausführt, muss über das Netzwerk mit Ihrer Datenbank kommunizieren. Vielleicht spricht es mit Ihrer Datenbank und es möchte, dass ein bestimmter Satz von Daten zurück an sie zurückgegeben wird. Und das kann einige Zeit in Anspruch nehmen, besonders wenn es sich um eine Menge Daten handelt, die Sie aus Ihrer Datenbank zurückziehen möchten. Es könnte ein paar Sekunden oder sogar ein paar Minuten dauern. Und während Ihre Datenbank das tut, während sie die Daten sammelt, sind Sie ein Thread, der nur dort wartet und nichts tut. Und das brennt wertvolle Zeit auf der CPU, die für einen anderen Thread verwendet werden könnte , der tatsächlich Code ausführen kann. Und so werden Sie detaillierter sehen, wie das alles in den kommenden Videos in diesem Kurs funktionieren wird. Und noch einmal habe ich ein Diagramm, nur um alles in einem visuellen Format zu zeigen. Und noch einmal, lassen Sie mich zurück aus dem PowerPoint hier, damit Sie meinen Cursor sehen können. So sehr ähnliches Konzept. Diese blaue Box stellt Ihren gesamten Prozess dar. Und in diesem Fall haben wir drei verschiedene Threads, die drei verschiedene Ausführungsflüsse desselben Codes ausführen. Und wie gesagt, jeder Thread hat seinen eigenen Stack-Raum, seine eigene unabhängige Ausführung Ihres Codes. Aber wie Sie in diesem lila gepunkteten Feld sehen können, teilen diese Threads die gleichen Daten oder statischen Abschnitt Ihres Speichers. Sie zeigen den Heap-Raum an und sie teilen auch den Code- oder Textabschnitt. Und hoffentlich sollte dieses Design für Sie einen Sinn ergeben, oder? Ich denke, es ist ziemlich offensichtlich, dass alle diese Threads denselben Codeabschnitt teilen sollten , weil sie alle denselben exakten Code ausführen. Jetzt können sie sich an verschiedenen Orten der Ausführung befinden, aber es gibt immer noch alle, die denselben exakten Code ausführen. Und dann für die Daten oder statischen Abschnitt, wir sind die globalen Konstanten oder globale Variablen sind gut mit ihrem Namen gespeichert. Dies sind globale Variablen, die globale Konstanten sind. Also sollte alles hier drin über die Barrieren hinausgehen, die vorhanden sind. Isolieren Sie jede einzelne Threads-Ausführung. Alle Threads sollten Zugriff auf die gleichen globalen Konstanten und globalen Variablen haben. Und dann für den Heap-Raum ist das etwas nuancierter. Sie könnten argumentieren, dass vielleicht jeder Thread auch seinen eigenen Heap-Raum haben sollte. Aber der Heap-Raum ist eine gute Möglichkeit Threads miteinander zu kommunizieren, oder? Vielleicht erstellt dieser Thread ein Objekt irgendeiner Art, vielleicht eine HashMap, und dieses Objekt würde im Heap-Raum gespeichert werden. Und dann möchte dieser Thread vielleicht auf etwas in dieser Karte zugreifen oder etwas hineinlegen. Nun, es kann einfach in diesen gemeinsamen Heap-Raum gehen und das tun. Und dann kann der erste Thread sehen, was der zweite Thread getan hat. Wie hat es diese HashMap manipuliert? Und dann kann es diese Informationen für die eigene Ausführung des Codes verwenden. Auch hier ist der Heap-Raum eine gute Möglichkeit Threads miteinander zu kommunizieren. Genau so würde eine Multithread-Anwendung oder ein Multithread-Prozess aussehen. Und das ist, was es Ihrem Computerprogramm ermöglicht, viel Multitasking zu tun, um eine Menge Dinge gleichzeitig zu tun. Und natürlich, wie ich bereits sagte, dass wir eine Menge Beschleunigung in Ihre Anwendung einführen werden. Und so werde ich Ihnen im nächsten Video einige sehr grundlegende Beispiele zeigen, mit dem Ziel wie Threads tatsächlich funktionieren. Also danke fürs Ansehen, und wir sehen uns im nächsten. 3. Grundlegende Thread: Okay, willkommen zum nächsten Video in diesem Kurs. Und in diesem Video hier zeige ich Ihnen ein paar sehr einfache Beispiele , die zeigen, wie Threads tatsächlich funktionieren. Und was ich hier bereits geschrieben habe, ist nur eine sehr grundlegende Hauptfunktion, die im Goaling geschrieben wurde. Und so ist dies die Funktion, die ich ausführen werde, die Ihnen tatsächlich zeigt, wie die Beispiele funktionieren. Nun, bevor Sie hier beginnen, möchte ich nur sagen, dass, wenn Sie nicht wissen, Goaling, dann keine Sorge, es ist absolut nicht erforderlich, um das Goaling für diesen Kurs zu verstehen. Und das liegt daran, dass ein Ziel sehr leicht zu verstehen ist. Es ist eine sehr saubere Sprache. Und die Nummer zwei, ich werde Ihnen sehr detailliert erklären , wie der Code, den ich gerade schreiben werde, tatsächlich funktionieren wird. Also für dieses Beispiel hier werde ich eine neue Funktion erstellen. Diese Funktion wird die tatsächliche Arbeit enthalten , die entweder vom Hauptthread ausgeführt wird, über den ich in einer Sekunde oder anderen Threads sprechen werde. Also werde ich weitergehen und func schreiben und wir nennen unsere Funktion arbeiten. Und es wird einen Parameter aufnehmen und es wird eine ID sein, die Sie sehen werden, wie das in einer Sekunde funktioniert. Das wird also eine ganze Zahl sein, und das war's. So erstellen Sie tatsächlich eine Funktion und gehen Lang, es ist sehr einfach. Und jetzt in dieser Funktion werde ich einfach eine For-Schleife machen, die die Zahlen eins bis 10 ausdruckt. So kann ich eingeben für I gleich 1, I kleiner oder gleich 10, I plus, plus, und dann Klammern. Also im Grunde, was dies hier tun wird, ist eine Variable namens i zu erstellen , die es instanziieren wird, um den Wert von eins zu sein. Und jedes Mal, wenn diese Schleife iteriert, wird sie den Wert von I um eins erhöhen. Das ist, was ich plus plus bedeutet. Und das wird viel klarer, wenn ich diesen Code tatsächlich ausführe. Und so werden wir in dieser for-Schleife nur eine grundlegende Print-Anweisung haben. Also FMT dot print f. Und hier wird der ID-Parameter hier ins Spiel kommen. Also der Text, der von dieser Druckanweisung ausgedruckt wird, wird Thread Prozent d sein und Sie werden sehen, was das in einem Sekunden% d bedeutet, und dann ein Zeilenumbruch. Und so sind diese Prozent-D-Symbole im Grunde nur Platzhalter , die wir tatsächlich mit den Werten ausfüllen, die wir wollen. Und das D bedeutet speziell Ziffern. Das werden also Zahlen sein. Und weil wir zwei von ihnen hier haben, bedeutet das, dass wir zwei Argumente brauchen, zwei ganze Zahlen, um tatsächlich in die Nachricht hier platziert zu werden. Also wird der erste die ID sein, und der zweite wird ich sein. Und das war's. Das ist unsere Arbeitsfunktion. Und dann in der Hauptfunktion hier, werden wir es einfach nennen. Also geben wir einfach Arbeit ein und wir werden den Wert eines als unser Argument übergeben. Das ist der ID-Wert. Und das war's. Wir speichern die Akte. Und ich habe vergessen, das FMT-Paket zu importieren. Lassen Sie mich das schnell machen. Also hier werde ich Importklammern eingeben und dann FMT die Datei erneut speichern. Da gehen wir. Also im Grunde, was dieser Code tun wird, sobald sie arbeiten Funktion ausgeführt wird. Wir werden diese For-Schleife treffen, wo ich, wie gesagt, auf den Wert von eins initialisiert werden werde. Und so wird es in der ersten Iteration dieser Schleife den Nachrichten-Thread 1 ausdrucken, richtig? Weil die ID hier, die wir übergeben, eins ist. Thread also einen Doppelpunkt, und dann wird es den Wert von I ausdrucken, für die erste Iteration dieser Schleife eins sein wird. Und dann wird sich die ID für die zweite Iteration nicht ändern, aber ich werde um eins erhöht. Das bedeutet also, ich werde 2. Die zweite Nachricht, die gedruckt wird, wird also Thread eins, Doppelpunkt zwei, und dann so weiter und so weiter bis 10 erreicht werden. Als Demonstration, bringen wir das Terminal hier hoch. Und zuerst werden wir diesen Code kompilieren. Also tippen gehen Build. Und der Name der Datei ist Threads Punkt gehen, drücken Sie die Eingabetaste. Alles klar, es ist kompiliert und dann führen wir den Code hier aus. So Punkt Schrägstrich Threads. Da gehen wir. Wie ich schon sagte, wie Sie hier sehen können, haben wir 10 Nachrichten und sie wurden alle durch Drohung eines gedruckt. Jetzt, wie ich bereits erwähnt habe, gibt es einen Hauptthread, jedes Programm, jeder Prozess muss mindestens einen Thread haben , der die Bedrohung ist, die Ihren Code tatsächlich ausführt, oder? Und dieser erste Thread, der hochgefahren wird und Ihren Code beim ersten Mal ausführt, das ist der Hauptthread. Ob Ihr Prozess nur Single-Threaded ist, wenn es nur einen Thread gibt oder wenn Ihr Prozess Multithreaded ist, gibt es in beiden Fällen immer einen Hauptthread. Und so wieder, in diesem Fall haben wir nur einen einzigen Thread-Prozess. Es gibt nur den Hauptthread, der ausgeführt wird. Und wie Sie hier sehen können, ging es einfach durch diese For-Schleife und druckte Zahlen eins bis zehn aus. Sehr einfach. Also, was ich jetzt tun werde, ist, dass ich zwei weitere Threads vorstellen werde. Also werden wir immer noch den einen Hauptthread haben, der sich nie ändern wird. Aber darüber hinaus wir auch zwei weitere Neben-Threads haben. Also zurück zum Code hier. Und so beim Goaling hier ist die Art und Weise, wie Sie einen Thread erstellen, eigentlich sehr, sehr einfach. Alles, was Sie tun müssen, ist, bevor Sie einen Funktionsaufruf tätigen, das ist es. Wir werden eins arbeiten müssen, und dann machen wir es ein zweites Mal. Geh auch arbeiten. Also, was hier passieren wird, ist, wenn ich dieses Programm ausführe, der Haupt-Thread wird gestartet und es wird zuerst die Hauptfunktion ausführen. Und sobald die Hauptfunktion auf diese Linie kommt, geht zu starten oder eine völlig neue Tochterbedrohung zu schaffen. Und sobald dieser untergeordnete Thread bereit ist, wird dieser Thread mit der Ausführung der do work-Funktion beginnen. Und sobald das passiert, sobald dieser neue Thread diese for-Schleife ausführt, kann der Haupt-Thread weitergehen und mehr Code ausführen. Also kommt der Hauptthread dann zu dieser Zeile, mach auch Arbeit, und das startet einen anderen Thread. Welches wäre der dritte Gesamt-Thread in unserem Programm hier. Und sobald dieser dritte Thread läuft und wieder läuft, wird er auch die gleiche do work Funktion ausführen. , dass Sie hier sehen können, Ich hoffe, dass Sie hier sehen können,dass Threads im Grunde denselben exakten Code ausführen. Jetzt kann es einige subtile Unterschiede geben. In diesem Fall werden die Parameter, die wir übergeben, unterschiedlich sein. Die IDs werden grundsätzlich anders sein, aber der Code, der danach tatsächlich ausgeführt wird, ist identisch. Und so schließlich, sobald der Haupt-Thread mit dieser Linie fertig ist, sobald dieser Haupt-Thread gestartet ist, wird dieser zweite Neben-Thread vorwärts gehen. Und so werde ich endlich eine Print-Anweisung hier unten hinzufügen. Und die Nachricht ist, dass es Haupt-Thread gemacht wird. Und danach wird das Programm beendet. Und dann noch eine Sache, die ich hier tun werde, ist diese Schleife zu ändern, um stattdessen den ganzen Weg zu 100 zu gehen. Also, sobald jeder dieser Tochter-Threads gestartet wird und beginnt zu laufen, werden sie jeweils die Zahlen eins bis 100 durchlaufen und diese Nachricht ausdrucken. Lassen Sie uns endlich das Terminal hierher bringen und wir werden unseren Code einfach so kompilieren. Bevor ich das anlege, wird es tatsächlich etwas Seltsames geben, das hier passieren wird. Dieser Code hat tatsächlich ein Problem. Wenn ich also auf Ausführen klicke, sehen Sie nur, dass der Hauptthread ausgedruckt wird. Aber was ist mit den anderen Threads? Es ist gegen jeden Druck die Zahlen eins bis 100 jeder. Und so ist das Problem hier, dass der Hauptthread tatsächlich fertig ist. Es druckt diese Nachricht aus und beendet dann das gesamte Programm und tut dies, bevor diese anderen Threads tatsächlich ihre Schleifen beenden können. Und so ist dies ein sehr wichtiger Punkt, den Sie über den Hauptthread im Auge behalten möchten. Der Haupt-Thread ist im Grunde der Chef will, dass der Haupt-Thread fertig ist, das gesamte Programm ist fertig, und jeder andere Subventionen oder Thread, der läuft, wird sofort getötet. Also wieder, nur um hier zusammenzufassen, starten wir das Programm. Der Haupt-Thread führt die Hauptfunktion aus. Es startet zwei Tochter-Threads, und beide diese Threads gehen aus und sie laufen unabhängig auf separaten Prozessoren, richtig? Das bedeutet also, dass der Haupt-Thread und diese beiden Neben-Threads alle zur gleichen Zeit auf meinem Computer ausgeführt werden. Sie laufen nur auf verschiedenen Prozessoren. Und sobald diese beiden Threads erstellt sind und dieser Code ausgeführt wird, gibt es Schleifen durch ihre Zahlen. Dann kann der Haupt-Thread weitergehen und seinen eigenen Code hier unten ausführen. Also druckt diese Nachricht aus und dann beendet sie. Das ist der ganze Code, der noch übrig ist. Und wieder kommt der Hauptthread zu diesem Punkt. Es druckt seine Nachricht aus, bevor die beiden Subventionen oder Threads, die anderswo auf verschiedenen Prozessoren ausgeführt werden , tatsächlich die Ausführung ihres eigenen Codes beenden können. Und deshalb kam keine ihrer Druckaussagen heraus und wurde gedruckt, als ich das Programm lief. Was das jetzt bedeutet, ist, dass ich einen Weg finden muss, um den Haupt-Thread warten zu lassen, bis seine beiden Tochter-Threads fertig sind, bevor tatsächlich zur Print-Anweisung übergehe und dann das gesamte Programm beendet. Jetzt führe ich Thread-Synchronisation ein, was im Grunde bedeutet,dass wir alle Threads, die in diesem Programm ausgeführt werden, so koordinieren dass wir alle Threads, die in diesem Programm ausgeführt werden was im Grunde bedeutet,dass wir alle Threads, die in diesem Programm ausgeführt werden, so koordinierenmüssen, dass das gesamte Programm tatsächlich so ausgeführt wird, wie wir wollen. Denn gerade jetzt, wie Sie gerade gesehen haben, wird dieses Programm nicht ordnungsgemäß ausgeführt. Damit der Haupt-Thread tatsächlich darauf wartet, dass diese zu anderen Threads fertig sind, müssen wir eine Gewichtungsgruppe verwenden. Zuerst muss ich ein anderes Paket importieren und es wird Sink heißen. Und dann kann ich aus dem Spüle Paket eine Gewichtsgruppe erstellen. Und ich erkläre in einer Sekunde, was das bedeutet. Es wird also nur eine Variable sein. Ich nenne es kurz WG. Und wie ich schon sagte, wird eine Gewichtsgruppe genau so sein. Und was wake-Gruppe ist, es ist im Grunde nur ein Zähler, auf den jeder Thread zugreifen kann. Selbst wenn wir alle Threads in diesem Programm auf verschiedenen Prozessoren ausführen, auf der CPU auf meinem Computer, können sie immer noch alle auf die gleiche genaue Gewichtsgruppe oder den gleichen genauen Zähler zugreifen. Und jetzt werde ich das tun, werde ich diesen Zähler mit einem Wert von zwei initialisieren. Also kann ich einfach WG eingeben, zwei hinzufügen. Sehr einfach. Ich habe einen Zähler gemacht und es hat den Wert von zwei, Das war's. Und so ist der nächste Schritt, wenn diese Arbeitsfunktionen durch die Subvention oder Threads ausgeführt werden, die erstellt werden, ich werde auch diese Gewichtsgruppenvariable in die Funktion übergeben. Also zuerst in der eigentlichen Do Work-Funktion muss ich Platz für einen zweiten Parameter machen. Also wird es WG sein und es wird die Art einer Gewichtsgruppe haben, natürlich, genau so. Und dann kann ich jetzt mein neues Gewichtgruppenobjekt tatsächlich in diese Funktionsaufrufe übergeben. Hier drin. Ich gebe einfach Komma w g ein und dann dasselbe hier, Komma WAG. Mach dir keine Sorgen darüber, was diese Symbole bedeuten. Dieses kaufmännische Und-Zeichen und dieses Sternsymbol hier. Dies bedeutet im Grunde nur, dass ich die tatsächliche Speicheradresse übergebe , die dem entspricht, wo diese Gewichtsgruppe tatsächlich gespeichert ist, nicht nur eine Kopie des tatsächlichen Objekts selbst. Und das liegt daran, dass alle Threads genau auf dieselbe Gewichtsgruppe zugreifen, den exakt gleichen Zähler. Wir können also nicht mehrere Kopien des Zählers an verschiedenen Stellen im Speicher haben. Wir wollen nur einen Zähler an einem bestimmten Ort im Speicher. Und wir möchten, dass jeder einzelne Thread auf die genaue spezifische Adresse im Speicher zugreift. So können sie alle den gleichen Zähler verwenden. Okay, jetzt hier drin, sobald unsere neuen Threads diese for-Schleife ausgeführt haben, brauchen wir einen Weg für diese Threads, um zu signalisieren, dass sie fertig sind. Und die Art und Weise, wie wir das tun, ist, dass wir einfach WG Punkt eingegeben haben. Das war's. Und was das tun wird, ist, dass es die Zählung in unserer Wachgruppe um eins verringern wird. Also initialisiere ich zuerst die Zählung auf zwei. Und dann, sobald ein Thread diese for-Schleife beendet hat, und es ruft die W1-Funktion für unser Gewichtgruppenobjekt auf. Es wird die Anzahl in dieser Gewichtsgruppe um eins verringern. Also, wenn dieser erste Thread hier, der erstellt wird, wenn dieser zuerst beendet wird und er fertig aufruft, bedeutet das, dass die Zählung in unserer Aktivierungsgruppe von zwei zu eins geht. Und dann, sobald der andere Thread beendet ist und er auch beendet aufruft, wird das auch den Zähler von einem auf 0 reduzieren. Und jetzt endlich brauchen wir einen Weg für den Hauptthread, um tatsächlich zu wissen, wann diese anderen Threads tatsächlich fertig sind. Denn im Moment haben wir nur einen Zähler, der auf zwei initialisiert ist. Und dann haben wir unsere anderen Threads, die einfach den Zähler um eins dekrementieren. Nun, wie wird das für den Hauptthread nützlich sein? Und die Art und Weise, wie wir es nützlich machen, ist vor unserer letzten Druckaussage hier, nennen wir WG Punktgewicht. Also diese Funktion, diese Gewichtsfunktion wird ausgeführt und dann wird der Haupt-Thread stoppen, weil der Haupt-Thread derjenige ist, der diesen Gewichtsfunktionsaufruf tatsächlich ausführt. Also wird der Haupt-Thread aufhören. Es wird warten, bis der Zähler einen Wert von 0 hat. Also geben wir dem Zähler zuerst den Wert zwei. Dann startet der Hauptfaden sehr schnell zwei weitere Fäden. Kommt hier runter, wirft einen Blick auf den Wert, der in der Theke ist. Es ist wahrscheinlich immer noch zu, das ist nicht 0 offensichtlich. Also hört es auf, es wartet. Und dann, während die anderen beiden Subventionen oder Threads laufen und sie dort FOR-Schleifen ausführen. Sobald sie fertig sind, rufen sie offensichtlich die W1-Funktion auf der Gewichtsgruppe auf, verringert den Zähler um eins. Also natürlich, sobald beide Threads fertig sind, wird der Zähler von zwei nach unten auf 0 gehen. Und sobald das passiert, wird der Haupt-Thread weitergehen. Sie werden ausdrucken, es ist fertig Anweisung, und dann wird schließlich das gesamte Programm nicht mehr ausgeführt. Also lasst uns diese Datei hier speichern und das Terminal zurückbringen. Dort gehen wir, kompilieren den Code neu, und jetzt können wir ihn ausführen und es sollte gut funktionieren. Also drücken Sie Enter und da gehen wir. Wie Sie hier sehen können, beide Threads, beide dieser Subventionen oder Threads, die ich sagen sollte waren beide Threads, beide dieser Subventionen oder Threads, die ich sagen sollte, in der Lage, ihre for-Loops auszuführen und alle ihre Nachrichten auszudrucken, Zahlen eins bis 100. Scrollen wir hier nach oben. Und weil Thread zuerst erstellt wurde, können Sie deshalb zuerst die Druckanweisungen sehen, Thread 1 und Thread 1 und Thread 1, so weiter und so weiter. Wenn ich jetzt hier nach unten scrolle, können Sie die erste Nachricht von Thread 2 sehen. Und das geschah direkt, nachdem Thread 1 den Druck 27 beendet hatte. Also offensichtlich Thread 1 hat an dieser Stelle noch einen langen Weg zu gehen , um den ganzen Weg zu 100 zu beenden. Aber weil beide Threads nur dieses eine Terminal teilen, müssen sie sowohl konkurrieren als auch darum kämpfen, ihre Aussagen auszudrucken. Letztendlich bedeutet das, wenn ich den Code hier ausgeführt habe, dass Sie im Grunde einen Flip-Flop zwischen Thread 1 und Thread 2 bekommen und ihre Aussagen ausdrucken. Thread eins hat seine Nachrichten für eine ganze Weile ausgedruckt. Und dann Thread 2 muss drehen, dass Sie hier sehen können. Und ich werde weiter scrollen. Und dann zurück, um wieder eins zu fädeln, scrollen Sie weiter. Und dann bekam Thread 2 ein paar weitere Print-Anweisungen heraus. Zurück zu Thread eins, so weiter und so weiter. Wie ich schon sagte, es dreht sich nur zwischen den beiden Fäden hin und her. Verwechseln Sie dies jetzt nicht für die beiden Threads, die tatsächlich nicht gleichzeitig laufen. Sie sind, wie ich schon sagte, sie müssen einfach mit dem Versuch konkurrieren, ihre Aussagen an einem Terminal auszudrucken. Aber in Wirklichkeit laufen beide Threads genau zur gleichen Zeit. Und schließlich, sobald beide Threads Zahlen eins bis 100 ausgedruckt haben, sind sie zu diesem Zeitpunkt beide fertig, was dem Hauptthread anweist zu warten, und dann kann er seine letzte Nachricht ausdrucken. Das gesamte Programm wird dann beendet. Jetzt gibt es noch eine letzte Sache, die ich Ihnen hier in diesem Video zeigen möchte, was im Grunde beweisen wird, dass Multithreading Ihr Programm wirklich beschleunigen kann. Also, jetzt werde ich diese for-Schleife hier auskommentieren. Wir brauchen es nicht mehr. Also ein Schrägstrich Stern und dann Stern Schrägstrich schreiben. Dies verhindert grundsätzlich, dass dieser Code ausgeführt wird. Diese for-Schleife wird also nicht laufen. Und dann drunter, werden wir nur eine Zeile haben. Und es wird Zeit Dot-Schlaf sein. Und dann machen wir dreimal Zeitpunktsekunde. Und dann muss ich auch das Zeitpaket importieren. Da gehen wir. Also, was das tun wird, ist, wenn beide dieser Threads hochgedreht werden und sie laufen, werden sie diese Aussage treffen. Und sie werden im Grunde schlafen gehen. Sie werden nur drei volle Sekunden lang aufhören, die Ausführung zu beenden. Und das soll im Grunde nachahmen, vielleicht einen Anruf über das Netzwerk an Ihre Datenbank zu machen, richtig? habe ich im vorherigen Video erwähnt. Vielleicht möchten Sie mit Ihrer Datenbank kommunizieren, um einige Daten einzuholen , die einige Zeit in Anspruch nehmen können. Es kann ein paar Sekunden oder ein paar Minuten dauern. Und das soll das nachahmen, oder? Denn sobald Ihr Thread und macht diesen Aufruf an Ihre Datenbank sagen, Hey, ich will diese Daten. Der Thread muss einfach dort sitzen und warten und nichts tun , bis die Datenbank diese Daten zurückgibt. Und dann, was ich auch hier tun werde, ist, dass ich diese Go-Schlüsselwörter hier entfernen werde , weil ich zuerst den Hauptthread und nur den Hauptthread möchte , um diesen ganzen Code auszuführen. Also im Grunde wird all diese Gewichtsgruppen-Sachen nichts tun , denn jetzt, indem wir diese go-Schlüsselwörter entfernen, sind wir jetzt mit einer einzigen Thread-Anwendung oder einem einzigen Thread-Prozess, nur dem Haupt-Thread, übrig . Das heißt, sobald der Haupt-Thread zu diesem Punkt kommt, muss er selbst die Arbeitsfunktion ausführen, bedeutet, dass der Haupt-Thread drei Sekunden lang schlafen wird und dann aufwacht und weitergeht. Was dann bedeutet, dass es die Arbeitsfunktion ein zweites Mal ausführen wird. Was bedeutet, dass der Hauptthread wieder drei Sekunden schlafen muss. Und dann ist es endlich fertig. Das bedeutet also, dass die volle Laufzeit dieses Programms sechs Sekunden betragen sollte. Also speichere ich die Datei, bringe das Terminal zurück und lasse mich schnell den Bildschirm löschen und das hier rüber bewegen. Gehen Sie voran und kompilieren Sie den Code und führen Sie ihn aus. Und eigentlich werde ich diesen Zeitbefehl vorher hinzufügen. Dies zeichnet im Grunde nur die Laufzeit des Programms auf, das ich ausführen werde. Drücken Sie also die Eingabetaste, und es sollte 64 Sekunden dauern, bis dieses Ding fertig ist. Und da gehen wir. Laufzeit genau sechs Sekunden. Und wieder, das sollte Sinn machen, weil wir nur eine einzige Thread-Anwendung haben, nur den Hauptthread. Und der Hauptfaden muss jedes Mal zwei Mal für drei Sekunden schlafen. Also sechs Sekunden insgesamt. Und so endlich werde ich jetzt wieder die Go Keywords hinzufügen. Also geh Arbeit, mach Arbeit, genau wie vorher. Und jetzt werden wir zwei Neben-Threads starten lassen und sie werden jeweils für drei Sekunden unabhängig schlafen. Und sie werden das zur gleichen Zeit tun. Was bedeutet, jetzt sollte dieses Programm ausgeführt werden und nur drei Sekunden insgesamt, richtig? Weil dieser Sleep-Befehl nicht sequentiell vor nur mit dem Haupt-Thread ausgeführt wird. Die Hauptbedrohung musste drei Sekunden schlafen, dann aufwachen und dann wieder nacheinander für drei weitere Sekunden schlafen. Deshalb dauerte es insgesamt sechs Sekunden. Aber jetzt machen wir zwei Neben-Threads , die beide drei Sekunden gleichzeitig schlafen gehen. Also schließlich werden wir den Code speichern, das Terminal zurückbringen, und wir werden ihn kompilieren und dann ausführen. Und wie gesagt, das sollte genau drei Sekunden dauern. Jetzt. Da gehen wir, nur drei Sekunden. Jetzt können Sie sich vorstellen, ob Sie eine Multithread-Anwendung hatten oder jeder Thread Aufrufe an Ihre Datenbank tätigte oder irgendeine Art von Berechnung durchführte. Das ganze Zeug könnte zur gleichen Zeit passieren, nicht nacheinander. Und so natürlich, wenn Sie in der Lage sind, Multitasking, tun Sie mehrere Dinge auf einmal, Das wird Ihr Programm viel schneller laufen lassen. Und wenn das gesagt wird, wird das für dieses Video tun. Und im nächsten gehen wir die Dinge noch einen Schritt weiter. Und ich werde Ihnen zeigen, wie Sie einen Threadpool erstellen , der im Grunde eine Warteschlange ist, eine Warteschlange, die eine Reihe von Aufgaben oder zu erledigende Arbeit enthält. Und dann haben Sie einen Pool von Fäden. Oder Arbeiter könnten im Grunde Dutzende, Hunderte oder sogar Tausende von ihnen sein , die eine Aufgabe aus der Warteschlange greifen und ihre Arbeit unabhängig ausführen. So können Sie es im Grunde als eine Montagelinie von Arten vorstellen. Also sehe ich dich in der nächsten. Danke. 4. Einen Threadpool aufbauen: Okay, willkommen zurück zur letzten Lektion in diesem Kurs. Und jetzt in diesem Video hier werden wir einen Thread-Pool erstellen, aus dem vorherigen Video aufbauen wird, wo ich Ihnen ein paar Beispiele gezeigt habe , wie Threads im Allgemeinen funktionieren. Aber jetzt gehen wir noch einen Schritt weiter und wir werden dieses Design umsetzen, das Sie hier in diesem Bild sehen können. Und so ist ein Threadpool, konzeptionell gesprochen, sehr einfach. Es ist nur eine Sammlung von Threads oder eine Sammlung von Arbeitern, die nur dort sitzen und darauf warten, eine bestimmte Aufgabe oder einen Job zu erledigen. Es ist also einer Montagelinie sehr ähnlich. Diese Auftragswarteschlange stellt hier die Montagelinie , die die verschiedenen Aufgaben oder Arbeiten enthält, die ausgeführt werden sollen. Und dann warten Ihre Worker-Threads darauf, eine dieser Aufgaben aufzunehmen und abzuschließen. Und dann haben Sie natürlich hier drüben die Produzenten der Arbeit, die erledigt werden muss. Diese Jungs setzen also eine Aufgabe in die Job-Warteschlange, und sobald einer der Worker-Threads verfügbar ist, wird es frei, eine neue Aufgabe aufzunehmen. Es wird es aus der Warteschlange auswählen und dann diese Aufgabe ausführen. Dieses Modell hier ist also eine gute Möglichkeit, die Ausführung Ihres Programms zu beschleunigen. Wenn Ihr Programm viele verschiedene Dinge hat, die erledigt werden müssen. Und speziell, natürlich, wenn die Dinge, die erledigt werden, Ihr Programm zur gleichen Zeit durchgeführt werden kann, oder zumindest, diese Jobs sind völlig unabhängig, dann wäre dies ein großartiger Anwendungsfall, um einen Thread zu verwenden Pool. Endlich werden wir hierher kommen und einen erschaffen. Genau wie im letzten Video habe ich bereits einen sehr einfachen Go-Code geschrieben. So ziemlich nur die Hauptfunktion und ein paar Variablen hier, richtig? diesem Flugpaket können Sie zum Beispiel bestimmte Parameter in Ihr Programm übergeben, wenn Sie es ausführen. Und du wirst in einer Minute sehen, wie das alles funktioniert. Das erste, was wir hier tun müssen, ist, unsere Warteschlange zu erstellen, die alle verschiedenen Aufgaben oder Jobs halten wird , die erledigt werden müssen. Und so hier oben über der Hauptfunktion werde ich eine globale Variable erstellen, die dieses Q halten wird. Also kann ich einfach var für Variable eingeben und ich werde die Warteschlange Arbeitswarteschlange aufrufen , um es offensichtlich zu machen. Und der Datentyp dieser Warteschlange und des Ziels wird Chan Integer sein. Und nur für dein Bewusstsein, Chan ist die Abkürzung für Kanal, und der Kanal und das Goaling sind im Grunde nur ein q, außer es hat einige zusätzliche Funktionen, die es mehreren Threads erlauben , atomar darauf zuzugreifen. Grundsätzlich nur eins nach dem anderen, oder? Weil Sie zum Beispiel keine Threads möchten, die versuchen , denselben Job gleichzeitig zu greifen. Nur ein Job kann zu einem Thread gehen. Deshalb möchten Sie sicherstellen, dass die Datenstruktur, die Sie verwenden, die Azure-Warteschlange in der Lage ist, mehrere Threads zu verarbeiten und gleichzeitig auf die darin enthaltenen Inhalte zuzugreifen. also in diesem Fall mit einem Kanal Wennalso in diesem Fall mit einem Kanalzwei Threads gleichzeitig auf den Kanal oder die Warteschlange zugreifen sollten, wird nur einer Zugriff gewährt, um einen bestimmten Job aus der Warteschlange zu holen. Und sobald es seine Aufgabe hat, wird dem zweiten Thread Zugriff auf die Warteschlange gewährt. Und so jetzt der nächste Schritt ist, dass wir tatsächlich unsere q instanziieren müssen. Also in unserer Hauptfunktion hier, nachdem wir die Eingabeparameter gesammelt haben, werden wir nur Arbeit q gleich schreiben machen chan int Komma 1, 0, 0, 0, 0, 0. Diese integrierte Funktion, die mit dem Goaling kommt, ist das, was Sie verwenden, um tatsächlich eine Warteschlange oder eine andere Datenstruktur zu erstellen oder zu instanziieren. Und das 100 bedeutet, dass wir 100 Spots oder 100 Positionen in der Warteschlange zuweisen. Im Grunde kann dieses Q 100 Aufgaben gleichzeitig sitzen und warten. Und das ist definitiv mehr Platz, als wir brauchen, aber wir behalten es einfach bei 1000. Okay, als nächstes müssen wir eine neue Funktion erstellen, die unseren Workerpool oder unseren Threadpool erstellen wird . Diese Funktion wird also „create thread pool“ genannt. Und es wird zwei Argumente aufnehmen, und es wird es zu einer Ganzzahl machen, die der Anzahl der Threads entspricht , die wir erstellen möchten, der Anzahl der Arbeiter. Und dann, wie im letzten Video, muss es eine Gewichtsgruppe aufnehmen, denn so werden wir alle Threads koordinieren, die gleichzeitig laufen, potenziell. Also noch einmal, ich werde EWG kurz verwenden. Und die Art von natürlich wird eine Gewichtsgruppe sein. Und da gehen wir. Als nächstes werden wir hier eine for-Schleife erstellen , die tatsächlich alle diese Threads erstellt. Also werde ich für I gleich 1 eingeben, ich kleiner oder gleich num Threads, I plus, plus Klammern. Bevor wir den Thread tatsächlich erstellen, müssen wir den Zähler erhöhen, der in der wake-Gruppe ist, richtig? Wenn Sie sich aus dem letzten Video erinnern, muss dieser Zähler in der Gewichtsgruppe zunächst auf die genaue Anzahl der Threads eingestellt werden , die wir erstellen werden. Wenn wir 20 Threads haben, 20 Arbeiter in unserem Pool als der Gewichtsgruppenzähler auf 20 eingestellt werden. Also in diesem Fall können wir einfach WG Punkt hinzufügen ein eingeben. Also jetzt für jeden Thread, der erstellt wird werden wir den Zähler um eins erhöhen. Und dann unten können wir tippen gehen. Und natürlich müssen wir tatsächlich eine Do Work-Funktion haben, die diese Threads ausführen können. Der nächste Schritt besteht also darin, diese do work Funktion wieder zu erstellen. Also hier unten, ich tippe in Funk arbeiten. Und diese Funktion wird zwei Argumente annehmen. Es wird eine ID nehmen, genau wie im vorherigen Video, das wird eine ganze Zahl sein. Und dann wird es auch in der wake-Gruppe nehmen. Denn wieder müssen wir alle unsere Threads synchronisieren, um den Hauptthread benachrichtigen zu können, wenn sie alle fertig sind. Also sinc Punkt Gewichtsgruppe und dann Klammern wieder. Und das bedeutet, dass wir in unserer Create-Thread-Pool-Funktion den Aufruf von do work für jeden Thread, den wir erstellen, abschließen können. Und so werde ich in I übergeben, das wird die ID jedes Threads und der Gewichtsgruppe sein. Und da gehen wir. Also, wenn ich dieses Programm ausführe, und sagen wir, ich gebe die Anzahl von 20 für den Threads-Parameter. Das bedeutet, dass unser Programm hier 20 Threads, 20 separate Threads, abgesehen von den wichtigsten natürlich, und alle 20 dieser Threads werden laufen, die funktionieren. Also, jetzt zurück in unserer Hauptfunktion, nachdem wir die Arbeitswarteschlange instanziiert haben, können wir create thread pool aufrufen. Und wir werden den Num Threads Parameter übergeben. Das wird ihm passieren, wenn ich das Programm und die wake-Gruppe ausführe, die ich vergessen habe zu erstellen. Also, eigentlich über dem Wort Warteschlange, werde ich es hier schaffen. Ich werde eine var WG tun, sinken Punkt, Gewichtsgruppe. Da gehen wir. Jetzt, da ich die tatsächliche Gewichtsgruppe erstellt habe, kann ich sie hier an unsere Create Thread Pool-Funktion übergeben. Und noch einmal bedeutet dieses kaufmännische Und-Zeichen, dass ich die tatsächliche Speicheradresse übergebe , wo diese Gewichtsgruppe tatsächlich gespeichert ist. Und das ist wichtig, weil wir möchten, dass alle Threads auf dieselbe Gewichtsgruppe zugreifen. Zu diesem Zeitpunkt haben wir unseren Thread-Pool erstellt und unsere Job-Warteschlange erstellt. Aber jetzt müssen wir tatsächlich die Arbeit Produzenten schaffen. Kommen wir zurück und machen genau das. Also, jetzt unten hier unten sind arbeiten Funktion. Ich werde eine weitere Funktion namens q Arbeit erstellen. Und das ist die Funktion, die Aufgaben tatsächlich in die Arbeitswarteschlange bringt. Und es wird zwei Parameter oder zwei Argumente annehmen, von denen das erste Num-Aufgaben sein wird. Wie viele Jobs wollen wir also in die Warteschlange stellen? Und dann wird die zweite Schlafzeit sein, die auch eine ganze Zahl sein wird. Und da gehen wir. So wie im letzten Video, um Arbeit zu simulieren oder zu imitieren, die tatsächlich ausgeführt wird, wir nur unseren Threadpool oder jeden einzelnen Threads innerhalb dieses Pools haben. Wir werden sie für eine gewisse Zeit einschlafen lassen. Und das wird diese Threads darstellen, die tatsächlich für ein paar Sekunden arbeiten. Und tatsächlich werden beide Argumente in das Programm übergeben , sobald ich es ausführe, richtig? Sie können die Schlafzeit hier und NAM-Aufgaben sehen. Diese Funktionen können also sehr einfach sein. Wir werden noch eine for-Schleife haben. Also werde ich sagen, für I gleich 0, ich weniger als num Aufgaben, ich plus, plus Klammern. Und die Art und Weise in Golan Sie etwas in eine Arbeitswarteschlange oder einen Kanal, den ich sagen sollte, ist, dass wir einfach den Namen des Wortes Warteschlange eingeben, wo Q. Und dann machen wir dieses kleine Pfeilsymbol. Und dann schreibe ich endlich Schlafzeit. Nehmen wir zum Beispiel an, num Aufgaben ist 20. Wir haben insgesamt 20 Aufgaben, die die Worker-Threads erledigen müssen. Und jede Aufgabe, die wir an die Warteschlange übergeben, entspricht einfach der Zeit, die jeder Thread schlafen soll. Wenn die Schlafzeit also drei Sekunden beträgt, werden wir die Nummer 3, 20 Mal in die Warteschlange geben . Und für jeden Arbeiter, der diese Zahl aufnimmt, die Nummer drei, wird er dann Schlaf für drei Sekunden bemerken. Und dann, wenn das unter der for-Schleife getan wird, nachdem es abgeschlossen ist, werden wir in der engen Arbeitswarteschlange eingeben. Und diese schließende Funktion hier zeigt einfach an , dass wir keine Arbeit mehr in die Warteschlange stellen werden. Wir schließen die Warteschlange. Und das ist sehr wichtig. Sie können dies nicht vergessen, denn wenn Sie es vergessen, haben Arbeiter in einem Threadpool keine Ahnung wann Sie aufhören müssen, mehr Arbeit aus der Warteschlange zu holen. Sie werden einfach weiter da sitzen und ewig warten. Also noch einmal, Sie brauchen einen Weg, um anzuzeigen, dass es keine Arbeit mehr zu tun gibt. Das ist also unsere q-Arbeitsfunktion. Und dann wieder in unserer Hauptfunktion, können wir es nennen. Also werde ich Warteschlangenarbeit eingeben und ich werde Num-Aufgaben und Schlafzeit einfach so übergeben. Und so haben wir endlich zwei weitere Hauptschritte zu erledigen. Die nächste besteht darin, die do work Funktion auszufüllen. Sie also noch einmal daran, dass jeder einzelne Thread, den wir erstellen, diese Funktion ausführen wird, von denen einige zur gleichen Zeit. Jetzt werde ich sagen, wenn wir vielleicht 100 Threads erstellen, na ja, ich habe keine 100 Prozessoren auf der CPU meines Computers. Ich habe nur acht. So können wir höchstens acht Threads gleichzeitig ausführen. Sie aber auch daran, dass ein Thread, sobald er in den Ruhezustand geht, nicht mehr auf der CPU ausgeführt werden muss. In diesem Fall wird jeder schlafende Thread nur vollständig vom Prozessor entfernt. Und auf diese Weise wird es Platz für neuen Thread schaffen, auf die CPU kommen und anfangen zu laufen. Und ich erkläre das hier in einer Minute nochmal. Jeder Thread, der die Funktion do work ausführt, wird kontinuierlich versuchen , eine Aufgabe aus der Arbeitswarteschlange zu ziehen. Also geben wir für die Schlafzeit im Bereich des Arbeitsfarbtons ein. Wir machen Zeitpunktschlaf und dann Zeitpunktdauer, Schlafzeiten, Zeitpunktsekunde. Grundsätzlich wird jeder Thread, der die Arbeitsfunktion ausführt, kontinuierlich durchlaufen und versuchen, etwas aus der Arbeitswarteschlange zu ziehen. Und natürlich, was aus der Warteschlange kommt, ist eine gewisse Zeit, um tatsächlich schlafen zu gehen. Also zieht es diese Schlafzeit aus der Arbeitswarteschlange und dann schläft es nur für diese Zeit. Mach dir keine Sorgen über diese Zeitpunktdauer. Dies bedeutet einfach, die Schlafzeit in den richtigen Datentyp zu konvertieren, um tatsächlich mit dem Zeitpunkt-zweiten Datentyp zu multiplizieren. Aber wieder, zurück zu meinem früheren Beispiel. Nehmen wir an, die Schlafzeit beträgt drei, entspricht drei Sekunden. Das bedeutet, wenn diese Funktion ausgeführt wird, wird jeder Thread für drei Sekunden schlafen. Das war's. Sobald die Arbeitswarteschlange leer ist und wieder, werden die Threads wissen, dass das Wort Warteschlange leer ist, weil wir es geschlossen haben , nachdem wir fertig waren, Dinge in die Warteschlange zu legen. Dann wird diese for-Schleife zu diesem Zeitpunkt brechen. Und das letzte, was jeder Thread tun muss, ist, die Methode auf der Gewichtsgruppe aufzurufen, richtig? Denn wenn Sie sich aus dem vorherigen Video erinnern, das ausgeführt Funktion verringert den Zähler in der wake-Gruppe um eins. Und sobald der Zähler auf 0 runter ist , kennt der Hauptthread alle untergeordneten Threads, alle Worker-Threads, vollständig ausgeführt. Also endlich der letzte Schritt zurück in der Hauptfunktion. Nun, nachdem der Hauptthread den Worker-Pool erstellt hat, und nach dem Hauptthread, cuz alle zu erledigende Arbeit. Jetzt muss der Haupt-Thread warten. Es muss warten, bis alle Worker-Threads ihre Arbeit beendet haben. Also nennen wir es W G Punktgewicht, genau wie zuvor. Und dann, sobald alle Threads fertig sind, drucken wir eine Nachricht aus und die Nachricht wird Hauptthread fertig sein. Und eigentlich eine letzte, letzte Sache, wir sollten auch eine Nachricht von jedem der Worker-Threads ausdrucken , die tatsächlich ausgeführt werden. Also, bevor jeder in den Schlaf geht oder eine Nachricht direkt hier ausdruckt. So FMT Punkt drucken f. Und genau wie im vorherigen Video wird die Nachricht Thread Prozent d sein, wohin die ID gehen wird. Und dann sagen wir einfach Arbeit Punkt-Punkt-Punkt und dann Zeilenumbruch Zeichen, und dann übergeben wir die ID, den Thread. Also, da gehst du hin. An dieser Stelle sollten wir einen voll funktionsfähigen Threadpool haben. Lassen Sie mich fortfahren und speichern Sie die Datei, um sicherzustellen, dass es keine Fehler gibt. Und da gehen wir, Alles sieht gut aus. Also, jetzt gehen wir weiter und bringen das Terminal hier hoch, und wir werden das Programm starten. Also erster Schritt ist es, es zu kompilieren. Also geh build und die Dateien namens Threadpool dot kompilieren es. Da gehen wir. Und dann führen wir es jetzt mit Punktschräg-Thread-Pool aus. Und hier ist, wo ich jetzt die Parameter wie Schlafzeit, Anzahl der Aufgaben usw. in das Programm übergeben kann. Also für die Num-Aufgaben, lasst uns 100 machen. Dann machen wir für die Anzahl der Threads, die wir haben wollen, zehn. Jetzt haben wir in diesem Fall mehr Aufgaben, die erledigt werden müssen, als die Threads, die wir erstellen werden. Das bedeutet natürlich, dass jeder Thread mehrere Aufgaben ausführen muss. Und dann legen wir die Schlafzeit auf 1 Sekunde fest, was wiederum die Arbeit simuliert oder imitiert , die tatsächlich von jedem Worker-Thread ausgeführt wird. Also, jetzt drücke ich die Eingabetaste. Da gehen wir. Sie können sehen, dass jeder der 10 Threads kreativ wurde. Und sie erledigen alle ihre individuellen Aufgaben unabhängig voneinander. Und sollte fast getan werden. Und da gehen wir. So zum Beispiel, hier ist, was ich meine, wenn ich sagte, dass jeder Thread mehrere Aufgaben erledigen muss. Also Thread eins macht etwas Arbeit. Und nachdem ich seine Arbeit beendet habe, nahm es später eine neue Aufgabe auf der Straße auf und beendete diese Arbeit. Und bemerken Sie, wie schnell das gesamte Programm beendet ist. Es waren nur ein paar Sekunden. Wir hatten 100 Aufgaben zu erledigen, aber weil wir 10 Threads hatten, die diese Aufgaben ausführen , von denen einige gleichzeitig, erreichten wir eine Menge Beschleunigung im Gegensatz zu, wenn ich alles sequentiell erledige. Also, wenn ich jetzt die Anzahl Threads nur zu einem ändere, also jetzt nur ein Thread, der 100 Aufgaben abschließt wird es viel länger dauern. Wir sehen uns, da gehst du. Und ich werde das Programm an diesem Punkt töten , weil es einfach zu lange dauern wird. Also sehen Sie offensichtlich meinen Punkt hier. Alles nacheinander zu tun, wird viel langsamer sein , als eine Menge Dinge gleichzeitig zu tun, oder einfach die Dinge viel effizienter zu machen. Wie gesagt, wenn ein Thread diese Aufgabe aufnimmt und in den Ruhezustand geht, gibt es an diesem Punkt keinen Grund, dass sich dieser Thread auf der CPU befindet. Es tut nichts. Das Betriebssystem auf meinem Computer ist intelligent genug, um das zu wissen. Und es wird diesen Thread vorerst von der CPU entfernen, wodurch dann Platz für einen neuen Thread freigegeben wird, einen neuen Worker-Thread, der gerade eine neue Aufgabe aufgenommen hat , um auf die CPU zu kommen und zu laufen. Und dann, sobald ein schlafender Thread nach dieser 1 Sekunde wieder aufwacht, wird mein Betriebssystem das erkennen, diesen Thread wieder auf die CPU setzen, damit er seine Aufgabe beenden und dann eine neue aufnehmen kann. Also im Grunde zusammengefasst ist mein Betriebssystem intelligent genug zu wissen, dass jeder Thread, der Code tatsächlich ausführen muss, diesen Thread priorisiert und auf die CPU legt, damit er ausgeführt werden kann. Und in dem Moment, in dem Thread keinen Code mehr ausführt, wenn er nur schläft. beispielsweise in einer realen Situation ein Thread darauf wartete, Wennbeispielsweise in einer realen Situation ein Thread darauf wartete,dass eine entfernte Datenbank Daten an sie zurückgibt, weiß mein Betriebssystem, diesen Thread vorerst zu entfernen. Es gibt keine Notwendigkeit, es auf der CPU zu haben und nur Zeit zu verschwenden. Obwohl mein Computer möglicherweise nur acht Prozessoren hat, also technisch gesehen, könnten nur acht Threads gleichzeitig ausgeführt werden. Aber weil mein Betriebssystem alle Threads und mein Programm orchestriert. Es ist fast so, als ob alle Threads immer noch zur gleichen Zeit laufen, oder? Ich könnte 100 Threads oder tausend Worker-Threads erstellen. Und es wird immer noch scheinen, dass viele von ihnen gleichzeitig laufen, auch wenn sie es nicht sein mögen. Das funktioniert natürlich nur bis zu einem Limit. Sie können keine 10 Milliarden Threads haben und erwarten, dass sie alle scheinbar gleichzeitig laufen. Es gibt eine Decke, aber Sie verstehen meinen Punkt. Also, wenn das gesagt wird, das wird dieses Video einpacken. Ich hoffe, das hat alles Sinn ergeben. Und im letzten Video, das als nächstes erscheint, werde ich nur ein paar Dinge einpacken und dann schicke ich dich auf den Weg. Danke. 5. Wir kommen zum Ende: Okay, kann diesen Kurs beenden. Und mittlerweile sollten Sie über die grundlegenden Tools und Informationen verfügen, die Sie benötigen, um Multithread-Anwendungen zu entwerfen. Und um Ihnen dabei zu helfen, etwas Übung zu geben, können Sie sich das Kursprojekt unten ansehen. Und so, mit dem gesagt, vielen Dank, dass Sie sich diesen Kurs angesehen haben. Ich bin Scott Rennen wieder, und ich weiß jede und alle Rückmeldungen zu schätzen, die Sie haben können. Wenn Sie Fragen haben oder eine Klärung benötigen, lassen Sie es mich bitte im Diskussionsabschnitt dieses Kurses wissen, und ich werde mich so schnell wie möglich bei Ihnen melden. Bitte schauen Sie sich auch meine anderen Skillshare Kurse an. Ich habe ein paar andere Klassen zu Informatik-Themen zusätzlich zu vielen Kursen über Optionshandel und Börseninvestitionen. Und schließlich, bitte folgen Sie mir auf der Skillshare Plattform, so dass Sie für jede neue Klasse benachrichtigt werden, die ich veröffentlicht. Also nochmals vielen Dank für das Beobachten und glückliche Programmieren.