Потоки с областью видимости позволяют вам заимствовать что-то вне потока и использовать его внутри потока.Они не могут позволить вам сделать обратное (заимствовать что-то внутри нити и позволить ему убежать).
buffer.split_whitespace()
заимствует buffer
, которое было перемещено во внутреннее закрытие и являетсяследовательно, принадлежит текущей теме.Каждый word
является ссылкой со временем жизни, зависящим от buffer
, которое выйдет из области видимости при выходе из потока.(Базовый String
не уничтожен, но word
может заимствовать только у Arc
, у которого более короткое время жизни. То же самое будет верно, если вы только что клонировали String
).
Arc
и объемные нити несколько расходятся.Arc
используется, когда вы разделяете объект между потоками и хотите, чтобы объект был уничтожен при выходе из последнего потока.Вы вообще не знаете или не заботитесь, какая нить является той, которая уничтожит его, только то, что она разрушается.С другой стороны, потоки с областью действия используются, когда вы делаете знаете, где вещь должна быть уничтожена, и все потоки, которые хотят получить к ней доступ, должны обязательно завершиться до этого.Поскольку время жизни статически проверяется с помощью потоков с определенными областями, вы можете использовать обычные ссылки &
вместо Arc
.Это относится как к String
, так и к Mutex
.
Итак, давайте применим это:
let buffer = String::from("Hello World Hello Rust");
let frequency: Mutex<HashMap<&str, u32>> = Mutex::new(HashMap::new());
crossbeam::scope(|scope| {
for _ in 0..1 {
scope.spawn(|_| {
for word in buffer.split_whitespace() {
let mut frequency = frequency.lock().unwrap();
*frequency.entry(word).or_insert(0) += 1;
}
});
}
});
О, это было легко.Обратите внимание, что нет move
s, Arc
s и clone()
s, и frequency
будет содержать ссылки на buffer
, что, по-видимому, то, что вы хотели.Чтобы это работало, какой бы подход вы ни использовали для разделения строк, он также должен заимствовать исходный str
;у вас не может быть отдельного String
для каждого потока.
Предостережение
Я не совсем уверен, насколько ваш пример похож на исходный код.Приведенное выше решение устраняет проблему компиляции, но, как указывает Шепмастер:
Я бы добавил, что оригинальный алгоритм не очень эффективен, так как количество разногласий для HashMap
будет крайне,Скорее всего, для каждого потока будет гораздо эффективнее иметь HashMap
и объединять их в конце.[...] Примерно так
См. Также