Verstehen Sie Rusts Ansatz zur Parallelität, der auf dem Konzept der „furchtlosen Parallelität“ basiert.
Unter Parallelität versteht man die Fähigkeit eines Programms, mehrere Aufgaben gleichzeitig auf demselben CPU-Kern auszuführen. Gleichzeitige Aufgaben werden im Gegensatz zur Parallelität in überlappender Zeit ohne festgelegte Reihenfolge ausgeführt und abgeschlossen. wobei verschiedene Aufgaben oder Teilaufgaben derselben Aufgabe gleichzeitig auf Hardware mit mehreren ausgeführt werden Prozessoren.
Rust zeichnet sich durch seine Leistungsmerkmale und die sichere und effiziente Unterstützung der Parallelität aus. Rusts Ansatz zur Parallelität basiert auf dem Konzept der „furchtlosen Parallelität“, bei dem die Sprache darauf abzielt, das Schreiben sicher zu machen Gleichzeitiger Code durch sein Besitz- und Ausleihsystem, das zur Kompilierungszeit strenge Regeln durchsetzt, um Datenspuren zu verhindern und den Speicher sicherzustellen Sicherheit.
Parallelität in Rust verstehen
Rust bietet mehrere Parallelitätsprimitive zum Schreiben gleichzeitiger Programme, darunter Threads, Nachrichtenübermittlung, Mutexe, atomare Typen und async/await für asynchrone Programmierung.
Hier ist eine Übersicht über die Parallelitätsprimitive von Rust:
- Themen: Rust bietet eine std:: Thread Modul in seiner Standardbibliothek zum Erstellen und Verwalten von Threads. Sie können mit dem neue Threads erstellen Thread:: spawn Funktion. Der Thread:: spawn Nimmt einen Abschluss an, der den Code zur Ausführung enthält. Sie können auch Threads ausführen, die parallel ausgeführt werden können, und Rust stellt Synchronisierungsprimitive bereit, um deren Ausführung zu koordinieren. Der Kreditprüfer stellt sicher, dass Verweise nicht zu unerwartetem Verhalten führen.
- Nachrichtenübermittlung: Das Parallelitätsmodell von Rust unterstützt die Nachrichtenübermittlung zwischen Threads. Sie nutzen die über die implementierten Kanäle std:: sync:: mpsc Modul zur Nachrichtenübermittlung. Ein Kanal besteht aus einem Sender (Absender) und ein Empfänger (Empfänger). Threads können Nachrichten über den Sender senden und über den Empfänger empfangen. Dies bietet eine sichere und synchronisierte Art der Kommunikation zwischen Threads.
- Mutexe und Atomtypen: Rust bietet Synchronisierungsprimitive, einschließlich Mutexe (std:: sync:: Mutex) und Atomtypen (std:: sync:: atomar), um den exklusiven Zugriff auf die gemeinsame Datennutzung zu gewährleisten. Mutexe ermöglichen mehreren Threads den gleichzeitigen Zugriff auf Daten und verhindern gleichzeitig Datenrennen. Atomare Typen stellen atomare Operationen für gemeinsam genutzte Daten bereit, z. B. das Erhöhen eines Zählers, ohne dass eine explizite Sperre erforderlich ist.
- Async/Await und Futures: Rusts asynchron/erwarten Die Syntax bietet Funktionen zum Schreiben von asynchronem Code, den Sie gleichzeitig ausführen können. Asynchrone Programme bewältigen E/A-gebundene Aufgaben effizient, sodass Programme andere Aufgaben ausführen können, während sie auf andere E/A-Vorgänge warten. Rusts asynchron/erwarten Die Syntax basiert auf Futures und Sie können sie mit dem steuern async-std oder Tokio Laufzeitbibliotheken.
Rust-Threads sind leichtgewichtig und aufgrund des fehlenden Laufzeit-Overheads eignen sie sich gut für Hochleistungsanwendungen. Die Parallelitätsprimitive von Rust lassen sich nahtlos in mehrere Bibliotheken und Frameworks integrieren, um unterschiedliche Parallelitätsanforderungen zu erfüllen.
So verwenden Sie Spawn-Threads in Rust
Sie werden das verwenden std:: Thread Modul zum Erzeugen von Threads. Der std:: thread:: spawn Mit der Funktion können Sie einen neuen Thread erstellen, der gleichzeitig mit dem Hauptthread oder anderen vorhandenen Threads in Ihrem Programm ausgeführt wird.
So können Sie einen Thread mit dem erstellen std:: thread:: spawn Funktion:
verwenden std:: thread;
fnhauptsächlich() {
// Erzeuge einen neuen Thread
lassen thread_handle = thread:: spawn(|| {
// Im neuen Thread ausgeführter Code kommt hierher
println!(„Hallo aus dem neuen Thread!“);
});// Warten, bis der erzeugte Thread beendet ist
thread_handle.join().unwrap();
// Der im Hauptthread ausgeführte Code wird hier fortgesetzt
println!(„Hallo vom Hauptthread!“);
}
Der hauptsächlich Funktion erstellt einen neuen Thread mit dem Thread:: spawn Funktion, indem Sie einen Abschluss übergeben, der den Code für die Ausführung im Thread enthält (in diesem Fall ist der Abschluss eine anonyme Funktion). Der Abschluss gibt eine Meldung aus, die angibt, dass der neue Thread ausgeführt wird.
Der verbinden Methode auf der thread_handle Ermöglicht dem Hauptthread, darauf zu warten, dass der erzeugte Thread die Ausführung abschließt. Per Anruf verbindenstellt die Funktion sicher, dass der Hauptthread auf den Abschluss des erzeugten Threads wartet, bevor er fortfährt.
Sie können mehrere Threads erzeugen und eine Schleife oder eine andere verwenden Struktur zur Rostbekämpfung um mehrere Abschlüsse zu erstellen und für jeden Thread zu erzeugen.
verwenden std:: thread;
fnhauptsächlich() {
lassen num_threads = 5;lassenmut thread_handles = vec![];
für ich In0..num_threads {
lassen thread_handle = thread:: spawn(Umzug || {
println!(„Hallo vom Thread {}“, ich);
});
thread_handles.push (thread_handle);
}für handhaben In thread_handles {
handle.join().unwrap();
}
println!(„Alle Threads fertig!“);
}
Die for-Schleife erzeugt fünf Threads, denen jeweils eine eindeutige Kennung zugewiesen ist ich mit der Schleifenvariablen. Die Verschlüsse erfassen den Wert von ich mit dem Umzug Schlüsselwort, das es zu vermeiden gilt Eigentumsfragen, und das thread_handles Der Vektor speichert die Threads für später im verbinden Schleife.
Nachdem alle Threads erzeugt wurden, wird die hauptsächlich Funktion iteriert über die thread_handles Vektor, Anrufe verbinden auf jedem Handle und wartet auf die Ausführung aller Threads.
Weiterleiten von Nachrichten über Kanäle
Sie können Nachrichten über Threads mit Kanälen weiterleiten. Rust bietet Funktionen für die Nachrichtenübermittlung im std:: sync:: mpsc Modul. Hier, mpsc steht für „Multiple Producer, Single Consumer“ und ermöglicht die Kommunikation zwischen mehreren Threads durch das Senden und Empfangen von Nachrichten über Kanäle.
So implementieren Sie die Nachrichtenübermittlung über Kanäle der Inter-Thread-Kommunikation in Ihren Programmen:
verwenden std:: sync:: mpsc;
verwenden std:: thread;fnhauptsächlich() {
// Einen Kanal erstellen
lassen (Sender, Empfänger) = mpsc:: channel();// Einen Thread erzeugen
Thread:: spawn(Umzug || {
// Eine Nachricht über den Kanal senden
sender.send(„Hallo aus dem Thread!“).auspacken();
});
// Empfange die Nachricht im Hauptthread
lassen empfangene_message = Receiver.recv().unwrap();
println!(„Nachricht erhalten: {}“, empfangene_Nachricht);
}
Der hauptsächlich Funktion erstellt einen Kanal mit mpsc:: channel() das gibt a zurück Absender und ein Empfänger. Der Absender sendet Nachrichten an die Empfänger das die Nachrichten empfängt. Der hauptsächlich Die Funktion erzeugt weiterhin Threads und verschiebt den Besitz der Absender zum Threadschluss. Im Inneren des Fadenverschlusses befindet sich der sender.send() Die Funktion sendet eine Nachricht über den Kanal.
Der Receiver.recv() Die Funktion empfängt die Nachricht, indem sie die Ausführung anhält, bis der Thread die Nachricht empfangen hat. Der hauptsächlich Funktion gibt die Nachricht nach einem erfolgreichen Nachrichtenempfang an die Konsole aus.
Beachten Sie, dass das Senden einer Nachricht über den Kanal den Absender verbraucht. Wenn Sie Nachrichten aus mehreren Threads senden müssen, können Sie den Absender mit klonen sender.clone() Funktion.
Darüber hinaus ist die mpsc Das Modul bietet andere Methoden wie try_recv(), der nicht blockierend versucht, eine Nachricht zu empfangen, und iter(), der einen Iterator über die empfangenen Nachrichten erstellt.
Die Nachrichtenübermittlung über Kanäle bietet eine sichere und bequeme Möglichkeit, zwischen Threads zu kommunizieren und gleichzeitig Datenwettläufe zu vermeiden und eine ordnungsgemäße Synchronisierung sicherzustellen.
Das Eigentums- und Ausleihmodell von Rust garantiert Speichersicherheit
Rust kombiniert Besitz, Borrowing und den Borrow Checker, um ein robustes, sicheres und gleichzeitiges Programmier-Framework bereitzustellen.
Der Borrow-Checker fungiert als Sicherheitsnetz und erkennt potenzielle Probleme zur Kompilierungszeit, anstatt sich auf Laufzeitprüfungen oder Garbage Collection zu verlassen.