• Ethan Liu
    2021-11-16
    rust相比go在并发处理上 有什么优点和缺点?

    作者回复: 文中已经讲了,Rust 的优点是所有方案都支持,缺点是你需要考虑合适的场景用合适的工具,另外 Rust channel 在某些情况下性能不如 golang;golang 的优点是简单,CSP 一招鲜,大部分场景 channel 都能很好适用,缺点是遇到 channel 不好解决的问题,或者效率不高的问题,就比较尴尬

    
    7
  • D. D
    2021-11-14
    既然 Semaphore 是 Mutex 的推广,那么实现的思路应该有点类似。 参考老师文章中所说的 Mutex 的实现方法,实现 Semaphore 的一个思路是: 我们可以用一个 AtomicUsize 记录可用的 permits 的数量。在获取 permits 的时候,如果无法获取到足够的 permits,就把当前线程挂起,放入 Semaphore 的一个等待队列里。获取到 permits 的线程完成工作后退出临界区时,Semaphore 给等待队列发送信号,把队头的线程唤醒。 至于像图书馆那样的人数控制系统,tokio 的 Semaphore 文档中使用 Semaphore::acquire_owned 的例子可以说就是这种场景的模拟。

    作者回复: 👍

    
    2
  • Geek_b52974
    2021-12-17
    作業: use std::sync::Arc; use tokio::{sync::Semaphore, task::JoinHandle}; #[tokio::main] async fn main() { let library = Box::new(Library::new(3)); let mut tasks: Vec<JoinHandle<()>> = vec![]; for i in 0..10 { tasks.push(library.enter(move || println!("no: {}, borrow book", i))); } for task in tasks { task.await.unwrap(); } println!("{:?}", library.semaphore.available_permits()); } struct Library { semaphore: Arc<Semaphore>, } impl Library { fn new(capacity: usize) -> Self { Self { semaphore: Arc::new(Semaphore::new(capacity)), } } fn enter(&self, chore: impl Fn() + Send + 'static) -> JoinHandle<()> { let semaphore = self.semaphore.clone(); tokio::spawn(async move { // remove this you will get panic // semaphore.close(); println!("{} quota left", semaphore.available_permits()); let s = semaphore.acquire_owned().await.unwrap(); chore(); drop(s); }) } }
    展开

    作者回复: 👍

    
    1
  • 终生恻隐
    2021-11-12
    // [dependencies] // tokio = { version = "1", features = ["full"] } // chrono = "*" use tokio::sync::{Semaphore, TryAcquireError}; use std::sync::Arc; use std::thread; use std::time::Duration; use chrono::prelude::*; #[tokio::main] async fn main() { let semaphore = Arc::new(Semaphore::new(3)); let mut join_handles = Vec::new(); for c in 0..5 { let permit = semaphore.clone().acquire_owned().await.unwrap(); join_handles.push(tokio::spawn(async move { let local: DateTime<Local> = Local::now(); println!("count{} start time: {}", c+1, local); thread::sleep(Duration::new(10, 0)); drop(permit); })); } for handle in join_handles { handle.await.unwrap(); } }
    展开

    作者回复: Duration 有 from_secs / from_millis 等方法,不必用 Duration::new,这个接口不直观。

    
    1
  • Milittle
    2022-01-13
    cas是指令集指令提供的能力 一般语言封装的并发原语都是在这个基础上的

    作者回复: 对

    
    
  • 慕高迪
    2022-01-10
    感觉和java对应的功能,原理一致

    作者回复: 👍

    
    
  • 核桃
    2021-12-05
    另外关于Ordering那几个的区别,个人写代码的时候,绝大部分时候,要么最简单的Relaxed,要么最严格的SeqCst,剩下的,不一定考虑那么多,除非特殊需要才去查一下区别,平时记不住的。。。

    作者回复: 不分场合地使用 Relaxed,会导致不一致的更新;不分场合地使用 SeqCst,会导致性能问题。

    
    
  • 核桃
    2021-12-05
    理解一下,对于所谓的指令原子操作,在计算机底层里面,没记错就是中断总线关闭吧。 然后那段优化的代码,就是拿不到锁先while空转一下,这里就有点像java的自旋锁的概念那样。 当然这里为什么空转性能会比spin好,从系统的角度理解,空转没有调用系统调用,那么就没有太多的进程或者线程切换,而切换这个是涉及上下文变更的。不管进程还是线程,上下文切换的时候,其实五大结构都是要考虑的,例如信号量那些是否要保存起来等等,那样代码自然会大很多了。 不知道这样理解是否对哈。

    作者回复: 不是。atomic operation 是硬件提供的无法被中断打断的指令,并不是去关闭中断。 这里我们用 atomic 实现的 mutex,就是一个 spinlock。

    
    
  • Geek_b52974
    2021-11-16
    compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) 想问一下第三个参数 为何不是 acqRel,这样其他线程会知道吗?

    作者回复: 你可以详细看文档:https://doc.rust-lang.org/std/sync/atomic/struct.AtomicBool.html#method.compare_exchange

    
    
  • 罗杰
    2021-11-12
    CAS 的原理挺绕的,需要好好的消化,最近也在看“Go 并发实战课”,有一些互通的地方。

    作者回复: 嗯

    
    