相关疑难解决方法(0)

如何将对堆栈变量的引用传递给线程?

我正在编写一个WebSocket服务器,其中一个Web客户端连接到多线程计算机AI上下棋.WebSocket服务器想要将Logger对象传递给AI代码.该Logger对象将管理从AI到Web客户端的日志行.在Logger必须包含对客户端连接的参考.

我对生命周期如何与线程交互感到困惑.我用Wrapper类型参数化的结构重现了这个问题.该run_thread函数尝试解包该值并记录它.

use std::fmt::Debug;
use std::thread;

struct Wrapper<T: Debug> {
    val: T,
}

fn run_thread<T: Debug>(wrapper: Wrapper<T>) {
    let thr = thread::spawn(move || {
        println!("{:?}", wrapper.val);
    });

    thr.join();
}

fn main() {
    run_thread(Wrapper::<i32> { val: -1 });
}
Run Code Online (Sandbox Code Playgroud)

wrapper参数存在于堆栈中,并且它的生命周期不会延伸超过run_thread堆栈帧,即使该线程将在堆栈帧结束之前连接.我可以从堆栈中复制值:

use std::fmt::Debug;
use std::thread;

struct Wrapper<T: Debug + Send> {
    val: T,
}

fn run_thread<T: Debug + Send + 'static>(wrapper: Wrapper<T>) {
    let thr = thread::spawn(move || …
Run Code Online (Sandbox Code Playgroud)

rust

22
推荐指数
1
解决办法
3771
查看次数

多线程可以使用Rust闭包吗?

我希望能够让多个线程评估相同的闭包.我想到的应用程序是并行化数值集成,因此可以将函数域轻松拆分为N个块并交给线程.

这是一个简单的函数,它多次计算提供的闭包并平均结果:

use std::sync::mpsc;
use std::thread;

const THREAD_COUNT: u64 = 4;

fn average<F: Fn(f64) -> f64>(f: F) -> f64 {
    let (tx, rx) = mpsc::channel();
    for id in 0..THREAD_COUNT {
        let thread_tx = tx.clone();
        thread::spawn(move || {
            thread_tx.send(f(id as f64));
        });
    }

    let mut total = 0.0;
    for id in 0..THREAD_COUNT {
        total += rx.recv().unwrap();
    }
    total / THREAD_COUNT as f64
}

fn main() {
    average(|x: f64| -> f64 { x });
}
Run Code Online (Sandbox Code Playgroud)

当我编译时,我收到此错误:

error[E0277]: `F` cannot be sent between …
Run Code Online (Sandbox Code Playgroud)

concurrency multithreading closures rust

5
推荐指数
1
解决办法
2308
查看次数

同时可变地访问保证向量不相交的大向量的任意索引

语境

我遇到多个线程必须更新存储在共享向量中的对象的情况。但是,向量非常大,并且要更新的元素数量相对较少。

问题

在最小示例中,可以通过包含要更新的元素的索引的(哈希)集来标识要更新的元素集。因此,代码如下所示:

let mut big_vector_of_elements = generate_data_vector();

while has_things_to_do() {
    let indices_to_update = compute_indices();
    indices_to_update.par_iter() // Rayon parallel iteration
       .map(|index| big_vector_of_elements[index].mutate())
       .collect()?;
}
Run Code Online (Sandbox Code Playgroud)

Rust显然不允许这样做:big_vector_of_elements不能同时在多个线程中可变地借用。但是,将每个元素包装在例如Mutex锁中似乎是不必要的:如果没有明确的同步,这种特定情况将是安全的。由于索引来自一组,因此可以保证它们是不同的。par_iter在向量的相同元素上没有两次迭代。

重提我的问题

编写一个并行修改向量中元素的程序的最佳方法是什么,在这种情况下,同步已经通过选择索引来解决,但是编译器不理解后者呢?

接近最佳的解决方案是将所有元素包装big_vector_of_elements在某种假设的UncontendedMutex锁中,这是其变体,Mutex在无竞争的情况下非常快,并且在发生争用(甚至发生恐慌)时可能会花费任意长时间。理想情况下,an UncontendedMutex<T>的大小和对齐方式也应与Tany相同T

相关但不同的问题:

可以使用“使用人造丝的并行迭代器”,“使用chunks_mut”或“使用split_at_mut” 来回答多个问题:

这些答案在这里似乎无关紧要,因为这些解决方案意味着迭代整个big_vector_of_elements,然后针对每个元素弄清楚是否需要更改任何内容。从本质上讲,这意味着这样的解决方案如下所示:

let mut big_vector_of_elements = generate_data_vector();

while has_things_to_do() {
    let indices_to_update = compute_indices();
    for (index, mut element) in big_vector_of_elements.par_iter().enumerate() …
Run Code Online (Sandbox Code Playgroud)

vector rust thread-synchronization rayon

5
推荐指数
2
解决办法
222
查看次数

如何在不使用互斥锁的情况下从任意索引处的多个线程写入可变切片?

我有两个从另一个方法传递过来的切片:

fn example<T>(a1: &[T], a2: &mut [T]) {}
Run Code Online (Sandbox Code Playgroud)

我想a1使用多个线程进行处理,然后a2使用仅在每个线程执行时才知道的完全任意索引写入。我的算法保证索引是互斥的,所以没有数据竞争。

借用检查器不喜欢在线程之间共享可变引用,因为它不知道我们的算法所做的保证。我也收到lifetime 'static required rustc (E0621)错误。

那么如何在 Rust 中做到这一点呢?

回答

不要回答我的问题。

第一个问题的答案解决了范围问题,而不是访问任意互不相交的索引的问题。第二个问题的答案表明,as_slice_of_cells但由于上述原因,即任意访问,这在这里不起作用。第三个问题的答案同样暗示,as_slice_of_cells但同样,数组可以分成不相交的部分的假设在这里无法实现。第四个问题再次询问对数组进行分区,我们在这里不能这样做。这同样适用于第五个问题。

范围界定问题的一个答案(/sf/answers/4515197711/)实际上试图解决这个问题,但它并不建议使用横梁,并且建议的替代方案比此处的最佳答案更不安全。

multithreading rust

4
推荐指数
1
解决办法
441
查看次数

不同的线程可以写入同一Vec的不同部分吗?

我有10个线程Vec,长度为100.

我可以在0-9元素(例如,排序它们)上使用线程0,而线程1正在处理元素10-19等等吗?

或者我必须使用Vec<Vec<>>这个吗?(我宁愿避免,因为元素在内存中不再是连续的)

rust

3
推荐指数
1
解决办法
460
查看次数