Как Rayon предотвращает использование RefCell <T>, Cell <T>и Rc <T>между потоками? - PullRequest
0 голосов
/ 02 декабря 2018

В документации Rayon говорится, что она гарантирует, что использование Rayon API не приведет к гонкам данных.

Как компилятор может узнать, что метод, вызываемый замыканиями, не разделяет изменяемое состояние, например RefCell<T> и Cell<T>, или используя структуры, которые не являются потокобезопасными, например Rc<T>?

Я понимаю, что core::marker::Sync отмечает типы, которые безопасны для обмена между потоками, но я не понимаю, как тип Rayonдекларации и компилятор применяют его!

1 Ответ

0 голосов
/ 02 декабря 2018

Вы на самом деле ответили на свой вопрос - все замыкания, которые должны быть разделены между потоками, должны быть Sync, а API Rayon просто требует, чтобы они были Sync через границы черты.См., Например, документацию ParallelIterator::map(), в которой метод обозначен как

fn map<F, R>(self, map_op: F) -> Map<Self, F> where
    F: Fn(Self::Item) -> R + Sync + Send,
    R: Send, 

Здесь нет более глубокой магии - всякий раз, когда Rayon использует замыкание так, как этого требуетравным Sync, например, передав его API-интерфейсу более низкого уровня, Rayon ограничивает соответствующий тип параметра границей Sync.Это, в свою очередь, гарантирует, что все, что хранится внутри замыкания, является Sync, поэтому в замыкании нельзя хранить RefCell.

В подобных случаях вы также можете запросить объяснение у компилятора.,Например, если вы попытаетесь скомпилировать этот код

use std::cell::RefCell;
use rayon::prelude::*;

fn main() {
    let c = RefCell::new(5);
    let _ = [1, 2, 3]
        .par_iter()
        .map(|i| i * *c.borrow())
        .sum();
}

, вы получите эту ошибку ( детская площадка )

error[E0277]: `std::cell::RefCell<i32>` cannot be shared between threads safely
  --> src/main.rs:10:10
   |
10 |         .map(|i| i * *c.borrow())
   |          ^^^ `std::cell::RefCell<i32>` cannot be shared between threads safely
   |
   = help: within `[closure@src/main.rs:10:14: 10:33 c:&std::cell::RefCell<i32>]`, the trait `std::marker::Sync` is not implemented for `std::cell::RefCell<i32>`
   = note: required because it appears within the type `&std::cell::RefCell<i32>`
   = note: required because it appears within the type `[closure@src/main.rs:10:14: 10:33 c:&std::cell::RefCell<i32>]`

Хотя компилятор, к сожалению, не работает напрямуюупомяните черту, привязанную к параметру map(), он все еще указывает вам на соответствующий метод и объясняет, что ожидает закрытие равным Sync, и причину, по которой это не так.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...