Safe and efficient processing of concurrency is one of the purposes of Rust,which mainly solves the problem of high load bearing capacity of the server.
The concept of concurrent refers to the independent execution of different parts of the program, which is easily confused with the concept of parallel,which emphasizes “simultaneous execution”.
Concurrency often leads to parallelism.
This chapter describes programming concepts and details related to concurrency. A thread is a part of a program that runs independently. The difference between a thread and a process (process) is that a thread is a concept within a program, and a program is often executed in a process. In an environment with an operating system, processes are often scheduled alternately to execute, and threads are scheduled by the program within the process. As thread concurrency is likely to occur in parallel, deadlocks and delay errors that may be encountered in parallelism often occur in programs with concurrency mechanisms. In order to solve these problems, many other languages (such as Java, C #) use special runtime software to coordinate resources, but this undoubtedly greatly reduces the efficiency of program execution. Multi-threading is also supported at the bottom of the operating system, andthe language itself and its compiler do not have the ability to detect and avoid parallel errors, which is very stressful for developers. Developers need to spend a lot of energy to avoid errors. Rust does not depend on the run-time environment, as is the case with CplinkCure +. But Rust has designed tools in the language itself, including ownership mechanisms, to eliminate as many common errors as possible in the compilation phase, which is not available in other languages. But this does not mean that we can be careless when programming, so far the problems caused by concurrency have not been completely solved in the publicdomain, there may still be errors, concurrent programming should be as careful as possible! Pass through Rust Running result: The order of this result may change in some cases, but in general it is printed like this. This program has a child thread designed to print five lines of text, and the main thread prints three lines of text, but obviously with the end of the main thread Closures are anonymous functions that can be saved into variables or passed as arguments to other functions. The closure is equivalent to the Lambda expression in Rust in the following format: For example: Running result: Closures can omit type declarations using the Rust automatic type determination mechanism: The result has not changed. Running result: This is a common situation: It must be wrong to try to use the resources of the current function in the child thread! Because the ownership mechanism prohibits the emergence of such a dangerous situation, it will undermine the certainty of the destruction of resources by the ownership mechanism. We can use closures. One of the main tools to achieve message passing concurrency in Rust is channel, which consists of two parts, a sender (transmitter) and a receiver (receiver). Running result: The child thread got the sender of the main thread 7.22.1. Thread #
std::thread::spawn
function to create a new thread:Example #
use std::thread;
use std::time::Duration;
fn spawn_function() {
for i in 0..5 {
println!("spawned thread print {}", i);
thread::sleep(Duration::from_millis(1));
}
}
fn main() {
thread::spawn(spawn_function);
for i in 0..3 {
println!("main thread print {}", i);
thread::sleep(Duration::from_millis(1));
}
}
main thread print 0
spawned thread print 0
main thread print 1
spawned thread print 1
main thread print 2
spawned thread print 2
spawn
, the thread ends and does not complete all the printing.
std::thread::spawn
: The parameter of the function is a no-parameter function, but the above method is not recommended. We can use closures to pass the function as a parameter:Example #
use std::thread;
use std::time::Duration;
fn main() {
thread::spawn(\|\| {
for i in 0..5 {
println!("spawned thread print {}", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 0..3 {
println!("main thread print {}", i);
thread::sleep(Duration::from_millis(1));
}
}
|Parameter 1, Parameter 2,... | -> Return value type{
//Function body
}
Example #
fn main() {
let inc = \|num: i32\| -> i32 {
num + 1
};
println!("inc(5) = {}", inc(5));
}
inc(5) = 6
Example #
fn main() {
let inc = \|num\| {
num + 1
};
println!("inc(5) = {}", inc(5));
}
7.22.2. Join method #
Example #
use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(\|\| {
for i in 0..5 {
println!("spawned thread print {}", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 0..3 {
println!("main thread print {}", i);
thread::sleep(Duration::from_millis(1));
}
handle.join().unwrap();
}
main thread print 0
spawned thread print 0
spawned thread print 1
main thread print 1
spawned thread print 2
main thread print 2
spawned thread print 3
spawned thread print 4
join
method can cause the child thread to finish running and then stop running the program. 7.22.3. Move forced ownership transfer #
Example #
use std::thread;
fn main() {
let s = "hello";
let handle = thread::spawn(\|\| {
println!("{}", s);
});
handle.join().unwrap();
}
move
keyword to handle:Example #
use std::thread;
fn main() {
let s = "hello";
let handle = thread::spawn(move \|\| {
println!("{}", s);
});
handle.join().unwrap();
}
7.22.4. Message passing #
std::sync::mpsc
Contains methods for message delivery:Example #
use std::thread;
use std::sync::mpsc;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move \|\| {
let val = String::from("hi");
tx.send(val).unwrap();
});
let received = rx.recv().unwrap();
println!("Got: {}", received);
}
Got: hi
tx
and called its
send
method sends a string, and the main thread passes through the corresponding receiver
rx
got it.