Можно ли вызвать FnOnce из Fn без Mutex?

Fn может быть отправлено через канал, но FnOnce еще не может быть стабильным. Чтобы отправить FnOnce через канал, можно обернуть его в Fn, как показано ниже.

Однако для этого требуется Mutex, что приводит к раздражающим накладным расходам при масштабировании до очень высокой пропускной способности (т.е. Осязаемо, когда вы делаете это много, оно замедляется).

Есть ли еще один примитив параллелизма, который я мог бы использовать здесь, который был бы менее тяжеловесным? Возможно, с std::sync::atomic? Можно ли это сделать без блокировки?

Я не заинтересован в использовании ночных функций или ящиков, которые полагаются на неопределенное поведение.

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

struct RawFunc {
 data: Box<fn() +="" send="" 'static="">,
}

impl RawFunc {
 fn new<t>(inner: T) -> RawFunc
 where
 T: FnOnce() + Send + 'static,
 {
 let inner_lock = Mutex::new(Some(inner));
 return RawFunc {
 data: Box::new(move || match inner_lock.lock() {
 Ok(mut i) => (i.take().unwrap())(),
 Err(_) => {}
 }),
 };
 }

 fn invoke(self) {
 (self.data)()
 }
}

fn main() {
 // Local
 let x = RawFunc::new(move || {
 println!("Hello world");
 });
 x.invoke();

 // Via channel
 let (sx, rx) = mpsc::channel::<rawfunc>();
 sx.send(RawFunc::new(move || {
 println!("Hello world 2");
 })).unwrap();
 let output = rx.recv().unwrap();
 output.invoke();

 // In a thread
 let guard = thread::spawn(move || {
 let output = rx.recv().unwrap();
 output.invoke();
 });

 sx.send(RawFunc::new(move || {
 println!("Hello world 3!");
 })).unwrap();

 guard.join().unwrap();

 // Passing arbitrary data to a thread
 let (sx, rx) = mpsc::channel::<rawfunc>();
 let guard = thread::spawn(move || {
 let output = rx.recv().unwrap();
 output.invoke();
 });

 let bar = RawFunc::new(move || {
 println!("Moved func!");
 });
 let foo = String::from("Hello World 4");
 sx.send(RawFunc::new(move || {
 println!("Some moved data: {:?}", foo);
 bar.invoke();
 })).unwrap();

 guard.join().unwrap();
}
</rawfunc></rawfunc></t></fn()>

детская площадка

1 ответ

Автор курсивного ящика имел точно такую же проблему и решал ее со своей собственной чертой.

/// Asynchronous callback function trait.
///
/// Every 'FnOnce(&mut Cursive) -> () + Send' automatically
/// implements this.
///
/// This is a workaround only because 'Box<fnonce()>' is not
/// working and 'FnBox' is unstable.
pub trait CbFunc: Send {
 /// Calls the function.
 fn call_box(self: Box<self>, &mut Cursive);
}

impl<f: fnonce(&mut="" cursive)="" -=""> () + Send> CbFunc for F {
 fn call_box(self: Box<self>, siv: &mut Cursive) {
 (*self)(siv)
 }
}
</self></f:></self></fnonce()>

источник

Вот PR, где был введен код.

licensed under cc by-sa 3.0 with attribution.