multithreading - 为什么我的 Futures 没有最大化 CPU?

标签 multithreading rust multiprocessing threadpool fibers

我正在创建数百个下载同一个文件的请求(这是一个玩具示例)。当我用 Go 运行等效逻辑时,我得到 200% 的 CPU 使用率并在 ~5 秒内返回 w/800 个请求。在只有 100 个请求的 Rust 中,它花费了将近 5 秒并产生 16 个操作系统线程,CPU 利用率为 37%。

为什么会有这样的差异?

据我了解,如果我有一个 CpuPool 管理 Future 跨越 N 核心,这在功能上就是 Go 运行时/goroutine combo 正在做,只是通过光纤而不是 future 。

从 perf 数据来看,尽管有 ThreadPoolExecutor,我似乎只使用了 1 个核心。

extern crate curl;
extern crate fibers;
extern crate futures;
extern crate futures_cpupool;

use std::io::{Write, BufWriter};
use curl::easy::Easy;
use futures::future::*;
use std::fs::File;
use futures_cpupool::CpuPool;


fn make_file(x: i32, data: &mut Vec<u8>) {
    let f = File::create(format!("./data/{}.txt", x)).expect("Unable to open file");
    let mut writer = BufWriter::new(&f);
    writer.write_all(data.as_mut_slice()).unwrap();
}

fn collect_request(x: i32, url: &str) -> Result<i32, ()> {
    let mut data = Vec::new();
    let mut easy = Easy::new();
    easy.url(url).unwrap();
    {
        let mut transfer = easy.transfer();
        transfer
            .write_function(|d| {
                data.extend_from_slice(d);
                Ok(d.len())
            })
            .unwrap();
        transfer.perform().unwrap();

    }
    make_file(x, &mut data);
    Ok(x)
}

fn main() {
    let url = "https://en.wikipedia.org/wiki/Immanuel_Kant";
    let pool = CpuPool::new(16);
    let output_futures: Vec<_> = (0..100)
        .into_iter()
        .map(|ind| {
            pool.spawn_fn(move || {
                let output = collect_request(ind, url);
                output
            })
        })
        .collect();

    // println!("{:?}", output_futures.Item());
    for i in output_futures {
        i.wait().unwrap();
    }
}

My equivalent Go code

最佳答案

From what I understand, if I have a CpuPool managing Futures across N cores, this is functionally what the Go runtime/goroutine combo is doing, just via fibers instead of futures.

这是不正确的。 documentation for CpuPool states ,强调我的:

A thread pool intended to run CPU intensive work.

下载文件不是CPU 绑定(bind),它是 IO 绑定(bind)。您所做的就是启动许多线程,然后告诉每个线程在等待 IO 完成时阻塞。

相反,使用 tokio-curl ,它使 curl 库适应 Future 抽象。然后您可以完全删除线程池。这应该会大大提高您的吞吐量。

关于multithreading - 为什么我的 Futures 没有最大化 CPU?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46539826/

相关文章:

python - Python的queue.Queue get/put方法在阻塞时是否持有该队列的锁?

rust - 有没有办法直接消耗人造丝链而不先收集它?

c - 将 C 数组传递给 Rust 函数

Python、WSGI、多处理和共享数据

c - 让 children 等待直到收到 parent 的信号

multithreading - Kafka中的Worker Queue选项

java - 线程意外工作

collections - 有没有办法在 Rust 中使用堆栈上的集合?

python multiprocessing starmap vs apply_async,哪个更快?

java - JMM 中的因果关系要求