< 返回版块

viruscamp 发表于 2023-01-08 15:07

我想要写的函数签名

虽然不符合语法,但最接近我的本意

fn spmc_test_scope(
  make_worker: impl for<'a> Fn(i32, &'a Mutex<Vec<i32>>) -> impl FnOnce() + Send + 'a)

我想要跑的代码

use std::sync::Mutex;
use std::thread;
use std::time::{Instant, Duration};
use std::vec::Vec;

fn spmc_test_scope(
  make_worker: impl for<'a> Fn(i32, &'a Mutex<Vec<i32>>) -> impl FnOnce() + Send + 'a)
{
    let queue = Mutex::new(Vec::from_iter(0..32));
    let begin = Instant::now();
    thread::scope(|s| {
        for id in 0..4 {
            s.spawn(make_worker(id, &queue));
        }
    });
    println!("used: {} ns", Instant::now().duration_since(begin).as_micros());
}

fn main() {
    spmc_test_scope(|id, queue| move || {
        let mut count = 0;
        let mut sum = 0i64;
        while let Some(num) = { let num = queue.lock().unwrap().pop(); num } {
            sum += num as i64;
            count += 1;
            thread::sleep(Duration::new(0, 10));
        }
        println!("id:{id} count:{count} sum:{sum}");
    });

    spmc_test_scope(|id, queue| move || {
        let mut count = 0;
        let mut product = 1i64;
        while let Some(num) = { let num = queue.lock().unwrap().pop(); num } {
            product *= num as i64;
            count += 1;
            thread::sleep(Duration::new(0, 10));
        }
        println!("id:{id} count:{count} product:{product}");
    });
}

尝试

  1. 函数签名正确,实现报错在 thread::scope(|s| {
fn spmc_test_scope<'a, W, MW>(make_worker: MW)
   where W: FnOnce() + Send + 'a, MW: Fn(i32, &'a Mutex<Vec<i32>>) -> W
  1. 函数签名正确,调用错误,与想要的不符: where 里面的两个 'a 没有关系
fn spmc_test_scope<W, MW>(make_worker: MW)
   where for<'a> W: FnOnce() + Send + 'a, for<'a> MW: Fn(i32, &'a Mutex<Vec<i32>>) -> W
  1. type_alias_impl_trait 改下可以运行, 但 spmc_test_scope 不能多次调用, 因为 Worker<'a> 是一个类型,而不是泛型约束
type Worker<'a> = impl FnOnce() + Send + 'a;
fn spmc_test_scope<MW>(make_worker: MW)
  where for<'a> MW: Fn(i32, &'a Mutex<Vec<i32>>) -> Worker<'a>
  
type Worker<'a> = impl FnOnce() + Send + 'a;
fn spmc_test_scope(
   make_worker: impl for<'a> Fn(i32, &'a Mutex<Vec<i32>>) -> Worker<'a>)
#![feature(type_alias_impl_trait)]

use std::sync::Mutex;
use std::thread;
use std::time::{Instant, Duration};
use std::vec::Vec;

type Worker<'a> = impl FnOnce() + Send + 'a;
fn spmc_test_scope(
   make_worker: impl for<'a> Fn(i32, &'a Mutex<Vec<i32>>) -> Worker<'a>)
{
    let queue = Mutex::new(Vec::from_iter(0..32));
    let begin = Instant::now();
    thread::scope(|s| {
        for id in 0..4 {
            s.spawn(make_worker(id, &queue));
        }
    });
    println!("used: {} ns", Instant::now().duration_since(begin).as_micros());
}

fn main() {
    spmc_test_scope(|id, queue| move || {
        let mut count = 0;
        let mut sum = 0i64;
        while let Some(num) = { let num = queue.lock().unwrap().pop(); num } {
            sum += num as i64;
            count += 1;
            thread::sleep(Duration::new(0, 10));
        }
        println!("id:{id} count:{count} sum:{sum}");
    });
/*
    spmc_test_scope(|id, queue| move || {
        let mut count = 0;
        let mut product = 1i64;
        while let Some(num) = { let num = queue.lock().unwrap().pop(); num } {
            product *= num as i64;
            count += 1;
            thread::sleep(Duration::new(0, 10));
        }
        println!("id:{id} count:{count} product:{product}");
    });
*/
}

评论区

写评论
作者 viruscamp 2023-01-11 19:37

巧了,首页的新问题 【求助】 ITIFTR 和 opaque type 里面提到 #![feature(impl_trait_in_fn_trait_return)] 这一看就能解决我最早写出的定义的问题

#![feature(impl_trait_in_fn_trait_return)]

// 原来写错的
fn spmc_test_scope1(make_worker: impl for<'a> Fn(i32, &'a Mutex<Vec<i32>>) -> impl FnOnce() + Send + 'a) {}

// 我们已经知道最后一个 'a 是嵌套的返回值的, 查了下括号()竟然可以在类型里面提升优先级, 注意括号要包括 impl
fn spmc_test_scope2(make_worker: impl for<'a> Fn(i32, &'a Mutex<Vec<i32>>) -> (impl FnOnce() + Send + 'a)) {}

但结果还是报错, 根据这些issues
Tracking Issue for impl Trait as output type of Fn traits in function return position
Multiple nested impl Trait in trait method does not work
Fn trait doesn't allow impl returns (impl Fn() -> impl Trait), which is inconsistent with all other traits
看起来还没做好。

作者 viruscamp 2023-01-10 20:44

从功能实现的角度上讲,当然苦瓜小仔的一种改进的做法:playground 最好, 高效且容易理解。

fn spmc_test_scope(worker: impl Fn(i32, &Mutex<Vec<i32>>) + Sync) {
    let queue = Mutex::new(Vec::from_iter(0..32));
    let q = &queue;
    let w = &worker;
    thread::scope(|s| {
        for id in 0..4 {
            s.spawn(move || w(id, q));
        }
    });
}
spmc_test_scope(|id, queue| {
    let n = queue.lock().unwrap().pop();
    println!("{id} {n}");
});

我之前写的时候一时脑子发昏,才写出那种复杂的定义。
当然,Box<dyn>总能让他跑起来。
但是从语言律师的角度,for<T: SomeTrait>之类的语法,应该是有必要的。

fn spmc_test_scope<MW>(make_worker: MW)
where for<'a, W: FnOnce() + Send + 'a> MW: Fn(i32, &'a Mutex<Vec<i32>>) -> W
{
    let queue = Mutex::new(Vec::from_iter(0..32));
    let q = &queue;
    thread::scope(|s| {
        for id in 0..4 {
            s.spawn(make_worker(id, q));
        }
    });
}
spmc_test_scope(|id, queue| move || {
    let n = queue.lock().unwrap().pop();
    println!("{id} {n}");
});
lithbitren 2023-01-09 21:11

感觉是下面这个方法好,向闭包内传引用就解决生命周期的问题了。

--
👇
苦瓜小仔: 一种低效的做法:playground

type Work<'a> = Box<dyn FnOnce() + Send + 'a>;
fn spmc_test_scope(make_worker: impl Fn(i32, &Mutex<Vec<i32>>) -> Work) {

一种改进的做法:playground

fn spmc_test_scope(make_worker: impl Fn(i32, &Mutex<Vec<i32>>) + Send + Sync) {
araraloren 2023-01-09 16:54

一个可行的方法

use std::marker::PhantomData;
use std::sync::Mutex;
use std::thread;
use std::time::{Duration, Instant};
use std::vec::Vec;

pub struct Wrap<'a>(Box<dyn FnOnce() + Send + 'a>);

pub struct WrapT<'a, T: FnOnce() + Send>(pub T, PhantomData<&'a ()>);

fn spmc_test_scope<M>(make_worker: M)
where
    M: for<'a> Fn(i32, &'a Mutex<Vec<i32>>) -> Wrap<'a>,
{
    let queue = Mutex::new(Vec::from_iter(0..32));
    let begin = Instant::now();

    thread::scope(|s| {
        for id in 0..4 {
            let wrapper = make_worker(id, &queue);

            s.spawn(wrapper.0);
        }
    });
    println!(
        "used: {} ns",
        Instant::now().duration_since(begin).as_micros()
    );
}

fn create_worker<'a>(id: i32, queue: &'a Mutex<Vec<i32>>) -> Wrap<'a> {
    Wrap(Box::new(move || {
        let mut count = 0;
        let mut sum = 0i64;
        while let Some(num) = {
            let num = queue.lock().unwrap().pop();
            num
        } {
            sum += num as i64;
            count += 1;
            thread::sleep(Duration::new(0, 10));
        }
        println!("id:{id} count:{count} sum:{sum}");
    }))
}

fn create_worker_t<'a>(
    id: i32,
    queue: &'a Mutex<Vec<i32>>,
) -> WrapT<'a, impl FnOnce() + Send + 'a> {
    WrapT(
        move || {
            let mut count = 0;
            let mut sum = 0i64;
            while let Some(num) = {
                let num = queue.lock().unwrap().pop();
                num
            } {
                sum += num as i64;
                count += 1;
                thread::sleep(Duration::new(0, 10));
            }
            println!("id:{id} count:{count} sum:{sum}");
        },
        PhantomData::default(),
    )
}

fn main() {
    spmc_test_scope(create_worker);

    // spmc_test_scope(|id, queue| move || {
    //     let mut count = 0;
    //     let mut product = 1i64;
    //     while let Some(num) = { let num = queue.lock().unwrap().pop(); num } {
    //         product *= num as i64;
    //         count += 1;
    //         thread::sleep(Duration::new(0, 10));
    //     }
    //     println!("id:{id} count:{count} product:{product}");
    // });
}
作者 viruscamp 2023-01-09 14:47

官网 HRTB 的讨论里面提出过 for<T: SomeTrait> 的语法 issue#1481

按此语法应该可以写成这样

fn spmc_test_scope<MW>(make_worker: MW)
where
    for<'a, W: FnOnce() + Send + 'a> MW: Fn(i32, &'a Mutex<Vec<i32>>) -> W

这个讨论也类似于此问题,pnkfelix 在此收集大量的相关问题 issue#56537

--
👇
TLMegalovania: 在rust forum上有类似问题么

ThalliMega 2023-01-09 13:09

在rust forum上有类似问题么

作者 viruscamp 2023-01-09 11:05

我知道下面的错在哪了, 最后的 + 'a , 本意是加在 W 上面, 但实际是加在 MW 上了

fn spmc_test_scope<W, MW>(make_worker: MW)
where
    W: FnOnce() + Send,
    for<'a> MW: Fn(i32, &'a Mutex<Vec<i32>>) -> W + 'a

那么再改写, 写清楚结合性, 但是语法错误

#![feature(unboxed_closures)]
fn spmc_test_scope<W, MW>(make_worker: MW)
where
    W: FnOnce() + Send, 
    for<'a> MW: Fn<(i32, &'a Mutex<Vec<i32>>), Output = W + 'a>

设想的语法, 对多个泛型参数有效的 for<'a> 语法

fn spmc_test_scope<W, MW>(make_worker: MW)
where for<'a> <
    W: FnOnce() + Send + 'a,
    MW: Fn(i32, &'a Mutex<Vec<i32>>) -> W,
>

另一种设想的语法

fn spmc_test_scope<W, MW>(make_worker: MW)
where
    for<'x> W<'x>: FnOnce() + Send + 'x,
    for<'a> MW: Fn(i32, &'a Mutex<Vec<i32>>) -> W<'a>
苦瓜小仔 2023-01-08 21:35

一种低效的做法:playground

type Work<'a> = Box<dyn FnOnce() + Send + 'a>;
fn spmc_test_scope(make_worker: impl Fn(i32, &Mutex<Vec<i32>>) -> Work) {

一种改进的做法:playground

fn spmc_test_scope(make_worker: impl Fn(i32, &Mutex<Vec<i32>>) + Send + Sync) {
作者 viruscamp 2023-01-08 16:47

函数签名应该是对的.

不写任何生存期参数, 也是调用处报 lifetime may not live long enough

fn spmc_test_scope<W, MW>(make_worker: MW)
where W: FnOnce() + Send, MW: Fn(i32, &Mutex<Vec<i32>>) -> W

之前写过下面的,函数签名直接就报错,原来调一下 for<'a> 的位置就可以的啊

fn spmc_test_scope<W, MW>(make_worker: MW)
where W: FnOnce() + Send, MW: for<'a> Fn(i32, &'a Mutex<Vec<i32>>) -> W + 'a

--
👇
TLMegalovania: 4. lifetime may not live long enough

use std::sync::Mutex;
use std::thread;
use std::time::{Duration, Instant};
use std::vec::Vec;

fn spmc_test_scope<R, MW>(make_worker: MW)
where
    for<'a> MW: Fn(i32, &'a Mutex<Vec<i32>>) -> R + 'a,
    R: FnOnce() + Send,
{
    let queue = Mutex::new(Vec::from_iter(0..32));
    let begin = Instant::now();
    thread::scope(|s| {
        for id in 0..4 {
            s.spawn(make_worker(id, &queue));
        }
    });
    println!(
        "used: {} ns",
        Instant::now().duration_since(begin).as_micros()
    );
}

fn main() {
    spmc_test_scope(|id, queue| {
        move || {
            let mut count = 0;
            let mut sum = 0i64;
            while let Some(num) = {
                let num = queue.lock().unwrap().pop();
                num
            } {
                sum += num as i64;
                count += 1;
                thread::sleep(Duration::new(0, 10));
            }
            println!("id:{id} count:{count} sum:{sum}");
        }
    });

    spmc_test_scope(|id, queue| {
        move || {
            let mut count = 0;
            let mut product = 1i64;
            while let Some(num) = {
                let num = queue.lock().unwrap().pop();
                num
            } {
                product *= num as i64;
                count += 1;
                thread::sleep(Duration::new(0, 10));
            }
            println!("id:{id} count:{count} product:{product}");
        }
    });
}
ThalliMega 2023-01-08 16:11
  1. lifetime may not live long enough
use std::sync::Mutex;
use std::thread;
use std::time::{Duration, Instant};
use std::vec::Vec;

fn spmc_test_scope<R, MW>(make_worker: MW)
where
    for<'a> MW: Fn(i32, &'a Mutex<Vec<i32>>) -> R + 'a,
    R: FnOnce() + Send,
{
    let queue = Mutex::new(Vec::from_iter(0..32));
    let begin = Instant::now();
    thread::scope(|s| {
        for id in 0..4 {
            s.spawn(make_worker(id, &queue));
        }
    });
    println!(
        "used: {} ns",
        Instant::now().duration_since(begin).as_micros()
    );
}

fn main() {
    spmc_test_scope(|id, queue| {
        move || {
            let mut count = 0;
            let mut sum = 0i64;
            while let Some(num) = {
                let num = queue.lock().unwrap().pop();
                num
            } {
                sum += num as i64;
                count += 1;
                thread::sleep(Duration::new(0, 10));
            }
            println!("id:{id} count:{count} sum:{sum}");
        }
    });

    spmc_test_scope(|id, queue| {
        move || {
            let mut count = 0;
            let mut product = 1i64;
            while let Some(num) = {
                let num = queue.lock().unwrap().pop();
                num
            } {
                product *= num as i64;
                count += 1;
                thread::sleep(Duration::new(0, 10));
            }
            println!("id:{id} count:{count} product:{product}");
        }
    });
}
1 共 10 条评论, 1 页