スマートポインタ、並列プログラミング、レーヨン
スタック対ヒープ
スタックは関数の最後に掃除されます.ヒープを掃除するための指示は、コンパイラによって加えられるさびにあります.
ポインタ対スマートポインタ
ポインタ-メモリアドレスを格納するオブジェクトで、メモリ内の位置を参照します
スマートポインタ-他のメタデータを格納しながら追加機能を提供するポインタをシミュレートします
スマートポインタはDELEFとDROP特徴を実装する
スマートポインタ
ボックス
fn main() {
let b = Box::new(5);
// uses 'Deref coercion' - converts a type into a reference to another type
println!("b = {}", b);
}
fn main() {
let x = 5;
let y = Box::new(x);
assert_eq!(5, x);
assert_eq!(5, *y);
}
ドロップ
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data `{}`!", self.data);
}
}
fn main() {
let c = CustomSmartPointer {
data: String::from("my stuff"),
};
let d = CustomSmartPointer {
data: String::from("other stuff"),
};
println!("CustomSmartPointers created.");
}
手動でオブジェクトを削除できます.
fn main() {
let c = CustomSmartPointer {
data: String::from("some data"),
};
println!("CustomSmartPointer created.");
drop(c);
println!("CustomSmartPointer dropped before the end of main.");
}
スマートポインタを参照
我々がオブジェクトの複数の所有者を必要とするとき(グラフ-ノードが長いもう一つのノードがそれに対する端を持つので、リリースされることができません).
Lispライクリスト
enum List {
Cons(i32, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::rc::Rc;
fn main() {
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
let b = Cons(3, Rc::clone(&a));
let c = Cons(4, Rc::clone(&a));
}
フェルセル
ボックスとは異なり、所有者は実行時にチェックされます.
pub trait Messenger {
fn send(&self, msg: &str);
}
pub struct LimitTracker<'a, T: Messenger> {
messenger: &'a T,
value: usize,
max: usize,
}
impl<'a, T> LimitTracker<'a, T>
where
T: Messenger,
{
pub fn new(messenger: &T, max: usize) -> LimitTracker<T> {
LimitTracker {
messenger,
value: 0,
max,
}
}
pub fn set_value(&mut self, value: usize) {
self.value = value;
let percentage_of_max = self.value as f64 / self.max as f64;
if percentage_of_max >= 1.0 {
self.messenger.send("Error: You are over your quota!");
} else if percentage_of_max >= 0.9 {
self.messenger
.send("Urgent warning: You've used up over 90% of your quota!");
} else if percentage_of_max >= 0.75 {
self.messenger
.send("Warning: You've used up over 75% of your quota!");
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::cell::RefCell;
struct MockMessenger {
sent_messages: RefCell<Vec<String>>,
}
impl MockMessenger {
fn new() -> MockMessenger {
MockMessenger {
sent_messages: RefCell::new(vec![]),
}
}
}
impl Messenger for MockMessenger {
fn send(&self, message: &str) {
self.sent_messages.borrow_mut().push(String::from(message));
}
}
#[test]
fn it_sends_an_over_75_percent_warning_message() {
let mock_messenger = MockMessenger::new();
let mut limit_tracker = LimitTracker::new(&mock_messenger, 100);
limit_tracker.set_value(80);
assert_eq!(mock_messenger.sent_messages.borrow().len(), 1);
}
}
スレッド
use std::thread;
use std::time::Duration;
fn main() {
thread::spawn(|| {
for i in 1..10 {
println!("hi number {} from the spawned thread!", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {} from the main thread!", i);
thread::sleep(Duration::from_millis(1));
}
}
結合スレッド
use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("hi number {} from the spawned thread!", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {} from the main thread!", i);
thread::sleep(Duration::from_millis(1));
}
handle.join().unwrap();
}
スレッド間のデータ転送
use std::sync::mpsc;
use std::thread;
fn main() {
let (sender, receiver) = mpsc::channel();
thread::spawn(move || {
let val = String::from("hi");
sender.send(val).unwrap();
});
let received = receiver.recv().unwrap();
println!("Got: {}", received);
}
ミューテックス
use std::sync::Mutex;
fn main() {
let m = Mutex::new(5);
{
let mut num = m.lock().unwrap();
*num = 6;
}
println!("m = {:?}", m);
}
原子参照カウント
スレッドセーフ参照カウントポインタ.
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}
レーヨン図書館
[dependencies]
rayon = "1.4"
use rayon::prelude::*;
use std::borrow::Borrow;
/// Computes product of elements in vector in parallel
fn product_of_vec(input: &[i32]) -> i32 {
input.par_iter()
.map(|&i| i * i)
.sum()
}
fn main() {
let product = product_of_vec(vec![2, 4, 6].borrow());
println!("Product is {}", product);
}
結合する
use std::sync::mpsc::channel;
use rayon::prelude::*;
fn main() {
let (sender, receiver) = channel();
(0..5).into_par_iter().for_each_with(sender, |s, x| s.send(x).unwrap());
let mut res: Vec<_> = receiver.iter().collect();
res.sort();
assert_eq!(&res[..], &[0, 1, 2, 3, 4])
}
演習
ダイニング
導入
コンピューターサイエンスにおいて、ダイニング哲学者問題は、それらを解決するための同期問題とテクニックを説明するためにコンカレントアルゴリズム設計でしばしば使用される例問題です.
この問題についてはhereを読むことができます.
タスク
fn main() {
let b = Box::new(5);
// uses 'Deref coercion' - converts a type into a reference to another type
println!("b = {}", b);
}
fn main() {
let x = 5;
let y = Box::new(x);
assert_eq!(5, x);
assert_eq!(5, *y);
}
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data `{}`!", self.data);
}
}
fn main() {
let c = CustomSmartPointer {
data: String::from("my stuff"),
};
let d = CustomSmartPointer {
data: String::from("other stuff"),
};
println!("CustomSmartPointers created.");
}
fn main() {
let c = CustomSmartPointer {
data: String::from("some data"),
};
println!("CustomSmartPointer created.");
drop(c);
println!("CustomSmartPointer dropped before the end of main.");
}
enum List {
Cons(i32, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::rc::Rc;
fn main() {
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
let b = Cons(3, Rc::clone(&a));
let c = Cons(4, Rc::clone(&a));
}
pub trait Messenger {
fn send(&self, msg: &str);
}
pub struct LimitTracker<'a, T: Messenger> {
messenger: &'a T,
value: usize,
max: usize,
}
impl<'a, T> LimitTracker<'a, T>
where
T: Messenger,
{
pub fn new(messenger: &T, max: usize) -> LimitTracker<T> {
LimitTracker {
messenger,
value: 0,
max,
}
}
pub fn set_value(&mut self, value: usize) {
self.value = value;
let percentage_of_max = self.value as f64 / self.max as f64;
if percentage_of_max >= 1.0 {
self.messenger.send("Error: You are over your quota!");
} else if percentage_of_max >= 0.9 {
self.messenger
.send("Urgent warning: You've used up over 90% of your quota!");
} else if percentage_of_max >= 0.75 {
self.messenger
.send("Warning: You've used up over 75% of your quota!");
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::cell::RefCell;
struct MockMessenger {
sent_messages: RefCell<Vec<String>>,
}
impl MockMessenger {
fn new() -> MockMessenger {
MockMessenger {
sent_messages: RefCell::new(vec![]),
}
}
}
impl Messenger for MockMessenger {
fn send(&self, message: &str) {
self.sent_messages.borrow_mut().push(String::from(message));
}
}
#[test]
fn it_sends_an_over_75_percent_warning_message() {
let mock_messenger = MockMessenger::new();
let mut limit_tracker = LimitTracker::new(&mock_messenger, 100);
limit_tracker.set_value(80);
assert_eq!(mock_messenger.sent_messages.borrow().len(), 1);
}
}
use std::thread;
use std::time::Duration;
fn main() {
thread::spawn(|| {
for i in 1..10 {
println!("hi number {} from the spawned thread!", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {} from the main thread!", i);
thread::sleep(Duration::from_millis(1));
}
}
結合スレッド
use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("hi number {} from the spawned thread!", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {} from the main thread!", i);
thread::sleep(Duration::from_millis(1));
}
handle.join().unwrap();
}
スレッド間のデータ転送
use std::sync::mpsc;
use std::thread;
fn main() {
let (sender, receiver) = mpsc::channel();
thread::spawn(move || {
let val = String::from("hi");
sender.send(val).unwrap();
});
let received = receiver.recv().unwrap();
println!("Got: {}", received);
}
ミューテックス
use std::sync::Mutex;
fn main() {
let m = Mutex::new(5);
{
let mut num = m.lock().unwrap();
*num = 6;
}
println!("m = {:?}", m);
}
原子参照カウント
スレッドセーフ参照カウントポインタ.
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}
レーヨン図書館
[dependencies]
rayon = "1.4"
use rayon::prelude::*;
use std::borrow::Borrow;
/// Computes product of elements in vector in parallel
fn product_of_vec(input: &[i32]) -> i32 {
input.par_iter()
.map(|&i| i * i)
.sum()
}
fn main() {
let product = product_of_vec(vec![2, 4, 6].borrow());
println!("Product is {}", product);
}
結合する
use std::sync::mpsc::channel;
use rayon::prelude::*;
fn main() {
let (sender, receiver) = channel();
(0..5).into_par_iter().for_each_with(sender, |s, x| s.send(x).unwrap());
let mut res: Vec<_> = receiver.iter().collect();
res.sort();
assert_eq!(&res[..], &[0, 1, 2, 3, 4])
}
演習
ダイニング
導入
コンピューターサイエンスにおいて、ダイニング哲学者問題は、それらを解決するための同期問題とテクニックを説明するためにコンカレントアルゴリズム設計でしばしば使用される例問題です.
この問題についてはhereを読むことができます.
タスク
[dependencies]
rayon = "1.4"
use rayon::prelude::*;
use std::borrow::Borrow;
/// Computes product of elements in vector in parallel
fn product_of_vec(input: &[i32]) -> i32 {
input.par_iter()
.map(|&i| i * i)
.sum()
}
fn main() {
let product = product_of_vec(vec![2, 4, 6].borrow());
println!("Product is {}", product);
}
use std::sync::mpsc::channel;
use rayon::prelude::*;
fn main() {
let (sender, receiver) = channel();
(0..5).into_par_iter().for_each_with(sender, |s, x| s.send(x).unwrap());
let mut res: Vec<_> = receiver.iter().collect();
res.sort();
assert_eq!(&res[..], &[0, 1, 2, 3, 4])
}
ダイニング
導入
コンピューターサイエンスにおいて、ダイニング哲学者問題は、それらを解決するための同期問題とテクニックを説明するためにコンカレントアルゴリズム設計でしばしば使用される例問題です.
この問題についてはhereを読むことができます.
タスク
それぞれの哲学者のために
哲学者は、左右の棒
彼は両方の棒を持っていた後
ミリ秒の乱数
両方の棒
彼が考えている印刷
ミリ秒の乱数
彼が考えるのを止めた印刷
すべてのスレッドに参加
ボーナス
std::sync::mpsc::channel
を使います最後に
解決策
Dining philosophers
Githubで私の学習錆レポをチェック!
PETR 7555 / 学習錆
Reference
この問題について(スマートポインタ、並列プログラミング、レーヨン), 我々は、より多くの情報をここで見つけました https://dev.to/petr7555/rust-5-smart-pointers-parallel-programming-rayon-16ndテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol