为什么我的期货不能最大化CPU?

时间:2017-10-03 08:01:16

标签: multithreading rust multiprocessing threadpool fibers

我正在创建几百个下载相同文件的请求(这是一个玩具示例)。当我使用Go运行等效逻辑时,我获得200%的CPU使用率,并在~5秒内返回800个req​​s。在Rust只有100个req​​s,它需要将近5秒,并产生16个OS线程,CPU利用率为37%。

为什么会有这样的差异?

根据我的理解,如果我在 N 内核中CpuPool管理Future,这在功能上就是Go运行时/ goroutine组合正在做的事情,只需通过纤维而不是期货。

从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

1 个答案:

答案 0 :(得分:2)

  

根据我的理解,如果我在 N 内核中CpuPool管理Future,这在功能上就是Go运行时/ goroutine组合正在做的事情,只需通过纤维而不是期货。

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

  

用于运行 CPU密集型工作的线程池。

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

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