Rust 5 - 스마트 포인터, 병렬 프로그래밍, 레이온

32892 단어 rust

스택 대 힙



스택은 함수가 끝날 때 정리됩니다. 힙 청소에 대한 지침은 컴파일러에 의해 추가된 Rust에 있습니다.

포인터 대 스마트 포인터



포인터 - 메모리 주소를 저장하고 메모리의 위치를 ​​참조하는 객체

스마트 포인터 - 다른 메타데이터를 저장하고 추가 기능을 제공하면서 포인터를 시뮬레이션합니다.

스마트 포인터는 Deref 및 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.");
}

Rc - 참조 카운트 스마트 포인터



개체의 여러 소유자가 필요한 경우(그래프 - 다른 노드에 가장자리가 있는 한 노드를 해제할 수 없음).

리스프와 같은 목록:

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));
}

RefCell



Box와 달리 한 명의 소유자만 런타임에 소유권을 확인합니다.

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에 대한 자세한 내용을 읽을 수 있습니다.


  • 5명의 철학자가 있다
  • 5개의 스틱이 있습니다(기본값이 0인 뮤텍스로 표시됨)
  • 각 철학자에 대해 다음과 같은 새 스레드를 만듭니다.
  • 철학자가 왼쪽 및 오른쪽 스틱을 잠그려고 합니다
  • .
  • 두 개의 막대기를 모두 잡은 후 먹고 있다고 인쇄합니다.

  • 임의의 밀리초 동안 휴면
  • 식사를 중단했다는 인쇄, 증가 뮤텍스(각 포크가 사용된 횟수 카운터)

  • 두 스틱의 잠금 해제
  • 그가 생각하는 프린트

  • 임의의 밀리초 동안 휴면
  • 생각을 멈춘 프린트


  • 모든 스레드 조인
  • 각 스틱을 사용한 횟수를 인쇄합니다(20이어야 함)
  • .

    보너스


  • std::sync::mpsc::channel를 사용하여 모든 메시지를 먼저 수집합니다
  • .
  • 마지막에 모든 메시지 인쇄

  • 해결책



    Dining philosophers

    GitHub에서 내 학습 Rust 저장소를 확인하세요!


    펫7555 / 학습-녹


    좋은 웹페이지 즐겨찾기