0Pricing
Learn Rust Coding · Lektion

Furchtlose Nebenläufigkeit mit Threads

Vertiefen Sie sich in die Rust-Grundlagen der nebenläufigen Programmierung, einschließlich Threads und Nachrichtenübermittlung, und stellen Sie Daten-Race-Freiheit sicher.

Furchtlose Nebenläufigkeit mit Threads ist eine kostenlose Learn Rust Coding-Lektion auf CoddyKit. Dies ist Lektion 3 von 3. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Learn Rust Coding-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Learn Rust Coding-Kurs umfasst insgesamt 3 Lektionen.

Einführung in die Nebenläufigkeit

Willkommen bei Furchtlos nebenläufig programmieren mit Threads! In dieser Lektion lernen Sie, wie Ihre Rust-Programme mehrere Dinge gleichzeitig erledigen können.

Nebenläufigkeit bedeutet, mehrere Berechnungen scheinbar gleichzeitig auszuführen. Sie ist entscheidend für reaktionsfähige Anwendungen und die Nutzung moderner Mehrkernprozessoren.

  • Threads sind leichtgewichtige Ausführungseinheiten innerhalb eines Programms.
  • Jeder Thread kann einen separaten Teil Ihres Codes ausführen.
  • Das Ownership-System von Rust hilft, häufige Fehler bei nebenläufiger Programmierung zu verhindern.

Ihren ersten Thread erstellen

Rust stellt std::thread::spawn bereit, um neue Threads zu erstellen. Sie übergeben dieser Funktion eine Closure (eine anonyme Funktion), die den Code enthält, den der neue Thread ausführen soll.

Führen Sie dieses Beispiel aus, um Threads in Aktion zu sehen:

use std::thread;
use std::time::Duration;

fn main() {
  println!("Hello from the main thread!");

  thread::spawn(|| {
    for i in 1..=5 {
      println!("Hi number {} from the spawned thread!", i);
      thread::sleep(Duration::from_millis(1));
    }
  });

  for i in 1..=3 {
    println!("Hi number {} from the main thread!", i);
    thread::sleep(Duration::from_millis(1));
  }
}

Auf Threads mit `join` warten

Im letzten Beispiel wird der erzeugte Thread möglicherweise nicht beendet, bevor der Hauptthread endet. Das liegt daran, dass der Hauptthread standardmäßig nicht auf erzeugte Threads wartet.

Damit ein erzeugter Thread seine Arbeit abschließt, verwenden wir die Methode join() auf seinem JoinHandle. Dadurch wird der aktuelle Thread blockiert, bis der verbundene Thread beendet ist.

use std::thread;
use std::time::Duration;

fn main() {
  let handle = thread::spawn(|| {
    for i in 1..=5 {
      println!("Thread: {}", i);
      thread::sleep(Duration::from_millis(1));
    }
  });

  for i in 1..=3 {
    println!("Main: {}", i);
    thread::sleep(Duration::from_millis(1));
  }

  handle.join().unwrap(); // Wait for the spawned thread to finish
  println!("Spawned thread has finished!");
}

Daten in Threads verschieben

Wenn Sie innerhalb einer spawn-Closure Variablen aus der umgebenden Umgebung verwenden, kommen die Ownership-Regeln von Rust zum Einsatz. Standardmäßig versuchen Closures, Variablen auszuleihen.

Wenn der erzeugte Thread den Gültigkeitsbereich des Hauptthreads überlebt, in dem die Variable definiert wurde, kann dies zu einer Dangling Reference führen. Verwenden Sie zur Behebung das Schlüsselwort move vor den Parametern der Closure.

  • move zwingt die Closure, die Ownership der von ihr erfassten Variablen zu übernehmen.
  • Dadurch bleiben die Daten während der gesamten Lebensdauer des neuen Threads gültig.
use std::thread;

fn main() {
  let data = String::from("Hello from outer scope");

  let handle = thread::spawn(move || { // Use 'move' to take ownership of 'data'
    println!("Data in thread: {}", data);
  });

  handle.join().unwrap();
  // println!("Data after thread: {}", data); // This would cause a compile error!
  println!("Main thread finished.");
}

Kommunikation durch Nachrichtenübermittlung

Obwohl das direkte Teilen von Daten zwischen Threads (gemeinsam genutzter Zustand) in Rust möglich ist, erfordert es eine sorgfältige Synchronisierung (z. B. mit Mutex und Arc, die in anderen Lektionen behandelt werden).

Ein sichererer und oft einfacherer Ansatz für Nebenläufigkeit ist die Nachrichtenübermittlung. Threads kommunizieren, indem sie sich gegenseitig Nachrichten senden, und vermeiden so den direkten Zugriff auf gemeinsam genutzten Speicher.

  • Ein Thread sendet Daten.
  • Ein anderer Thread empfängt Daten.
  • Die Standardbibliothek von Rust stellt dafür std::sync::mpsc bereit.

Einen `mpsc`-Kanal einrichten

std::sync::mpsc steht für Multiple Producer, Single Consumer. Das bedeutet, dass viele Threads Nachrichten senden können, aber nur ein Thread sie empfangen kann.

Um einen Kanal zu erstellen, rufen Sie mpsc::channel() auf. Die Funktion gibt ein Tupel zurück, das Folgendes enthält:

  • Einen Sender (tx): Zum Senden von Nachrichten.
  • Einen Receiver (rx): Zum Empfangen von Nachrichten.

Sehen wir uns an, wie Sie einen Kanal erstellen und eine einfache Nachricht senden.

use std::sync::mpsc;
use std::thread;

fn main() {
  // Create a new channel
  let (tx, rx) = mpsc::channel();

  thread::spawn(move || {
    let val = String::from("hi");
    tx.send(val).unwrap(); // Send the message
    // println!("val is {}", val); // Error: val moved to tx.send()
  });

  // Receive the message in the main thread
  let received = rx.recv().unwrap();
  println!("Got: {}", received);
}

Mehrere Nachrichten senden

Sie können mehrere Nachrichten über denselben Kanal senden. Der Receiver stellt dafür Methoden bereit:

  • rx.recv(): Blockiert den aktuellen Thread, bis eine Nachricht empfangen wird. Gibt ein Result zurück.
  • rx.try_recv(): Nicht blockierend. Gibt sofort ein Result zurück, entweder mit einer Nachricht oder mit einem Fehler, wenn keine Nachricht verfügbar ist.
  • Sie können auch direkt über den Receiver iterieren, um Nachrichten abzurufen, bis der Sender geschlossen wird.
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

fn main() {
  let (tx, rx) = mpsc::channel();

  thread::spawn(move || {
    let msgs = vec!["hi", "from", "the", "thread"];
    for msg in msgs {
      tx.send(String::from(msg)).unwrap();
      thread::sleep(Duration::from_millis(10));
    }
  });

  // Iterate over the receiver to get all messages
  for received in rx {
    println!("Got: {}", received);
  }
  println!("All messages received!");
}

Mehrere Sender, ein Empfänger

Das „MP“ in mpsc steht für Multiple Producers. Sie können einen Sender klonen, damit mehrere Threads Nachrichten an denselben Receiver senden können.

Jeder geklonte Sender teilt den Zugriff auf denselben Kanal. Dadurch können verschiedene Threads gleichzeitig Nachrichten senden.

use std::sync::mpsc;
use std::thread;
use std::time::Duration;

fn main() {
  let (tx, rx) = mpsc::channel();

  let tx1 = tx.clone(); // Clone the sender for another thread
  thread::spawn(move || {
    tx1.send(String::from("hello from tx1")).unwrap();
  });

  thread::spawn(move || {
    tx.send(String::from("hello from tx2")).unwrap();
  });

  // Collect all messages
  let mut received_messages: Vec<String> = vec![];
  for received in rx {
    received_messages.push(received);
    if received_messages.len() == 2 { break; } // Assuming 2 messages for this example
  }
  println!("Received: {:?}", received_messages);
}

Furchtlose Nebenläufigkeit mit Rust

Das Ownership- und Typsystem von Rust ist entscheidend für furchtlose Nebenläufigkeit. Durch die Durchsetzung von Regeln zur Kompilierzeit verhindert Rust häufige Fehler bei nebenläufiger Programmierung, etwa Data Races.

  • Ownership verhindert mehrere veränderliche Referenzen auf dieselben Daten.
  • Das Schlüsselwort move stellt sicher, dass Daten sicher in einen neuen Thread übertragen werden.
  • Nachrichtenübermittlung (mpsc) kommt vollständig ohne gemeinsam genutzten Speicher aus und macht die Kommunikation dadurch standardmäßig sicher.

Mit diesen Mechanismen können Sie nebenläufigen Code zuverlässig schreiben, da der Compiler viele potenzielle Probleme erkennt.

Test zu Konzepten der Nebenläufigkeit

Welche der folgenden Aussagen über die Nebenläufigkeitsprimitive von Rust sind WAHR?

Rückblick: Threads und Nachrichtenübermittlung

Sehr gut! Sie haben die Grundlagen der furchtlosen Nebenläufigkeit in Rust kennengelernt:

  • Wir erstellen neue Threads mit std::thread::spawn.
  • Mit JoinHandle::join() warten wir, bis ein Thread beendet ist.
  • Das Schlüsselwort move überträgt die Ownership von Daten sicher in einen Thread.
  • std::sync::mpsc stellt ein robustes System zur Nachrichtenübermittlung zwischen Threads bereit.
  • Die Ownership-Regeln von Rust verhindern Data Races bereits zur Kompilierzeit und machen nebenläufige Programmierung sicherer.

Diese Lektion bietet eine solide Grundlage für die Entwicklung reaktionsfähiger und effizienter Anwendungen. Üben Sie weiter!

Häufig gestellte Fragen

Ist die Lektion „Furchtlose Nebenläufigkeit mit Threads“ kostenlos?

Ja — der vollständige Text von „Furchtlose Nebenläufigkeit mit Threads“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Learn Rust Coding-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Learn Rust Coding-Kurs umfasst insgesamt 3 Lektionen.

Was lerne ich in „Furchtlose Nebenläufigkeit mit Threads“?

Vertiefen Sie sich in die Rust-Grundlagen der nebenläufigen Programmierung, einschließlich Threads und Nachrichtenübermittlung, und stellen Sie Daten-Race-Freiheit sicher. Du übst Learn Rust Coding mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Learn Rust Coding zu starten?

Keine Vorkenntnisse erforderlich. Learn Rust Coding auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 3.

Wie lange dauert die Lektion „Furchtlose Nebenläufigkeit mit Threads“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Learn Rust Coding-Lektion Code schreiben und ausführen?

Ja. Jede Learn Rust Coding-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Intelligente Zeiger: Box, Rc und Arc
  2. Interior Mutability: RefCell, Cell
  3. Furchtlose Nebenläufigkeit mit Threads
← Zurück zu Learn Rust Coding