< 返回版块

WorldLink 发表于 2020-12-09 13:18

Tags:rust,并发,async_std,tokio,异步,go

golang 可以通过channl来实现并发数量的限制 如下

	// slice 存储当前需要处理的任务
	task := []string{
		"task1",
		"task2",
		"task3",
	}

	limit := make(chan bool,10) // 定义空间为10的chan作为限流器

	for i := range task {
		idx := i  // copy
		
		limit<-true  // 每次任务执行  塞入
		go func() {
			defer func() {
				<-limit  // 任务执行完毕 塞出
			}()
			// 处理任务
			fmt.Println("task: ",task[idx])
		}()
	}

rust 有什么好的解决方案呢? 我是这样写的

use async_std::task;
use std::time::Duration;
use async_std::channel;

#[async_std::main]
async fn main() {
    let mut task_list = Vec::new();
    for i in 0..10000 {
        task_list.push(format!("task: {}",i))
    }

    let (sen,rec) = channel::bounded(10);

    for i in task_list {
        sen.send(1).await;
        let rec = rec.clone();
        task::spawn(async move {
            task::sleep(Duration::from_millis(500)).await;
            println!("Processing {}",i);
            rec.recv().await;
        });
    }

    loop {
        task::sleep(Duration::from_secs(1)).await;
    }
}

如果使用上面方式解决 可能回出现处理task时发生异常以至于没有执行rec.recv().await

go通过defer 确定task处理完毕时必然回执行 处理令牌 , rust怎么解决呢?

使用一个结构体处理task 并重写它的Deref trait ?

评论区

写评论
Dennis-Zhang-SH 2020-12-10 10:13

可以控制一下服务访问的压力?

--
👇
AbdyCjen: 这种用令牌控制并发的方式相比直接用固定数量的线程(协程)从队列取里有什么优点吗?是为了避免执行线程崩溃导致的执行线程数变少甚至阻塞吗?

如果用令牌的话可以试下scopeguard这个库,里面实现了defer的部分功能,应该是能够满足你的需求的;

AbdyCjen 2020-12-10 03:09

这种用令牌控制并发的方式相比直接用固定数量的线程(协程)从队列取里有什么优点吗?是为了避免执行线程崩溃导致的执行线程数变少甚至阻塞吗?

如果用令牌的话可以试下scopeguard这个库,里面实现了defer的部分功能,应该是能够满足你的需求的;

lithbitren 2020-12-09 14:50

defer本身也有微小的性能影响,放在其他语言相当于做了try的finally阶段,把逻辑写进panic::catch_unwind可能也差不多(没在异步程序里试过

Ryan-Git 2020-12-09 14:42

是只会 go 么。。。

第一个功能就是信号量(semaphore),tokio 里就有。async-std 貌似没有,但自己用 mutex, condition 封装一下也很简单。

第二个 defer 类似 RAII,实现 drop 就行。

1 共 4 条评论, 1 页