Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 为什么我的未来不能最大化CPU?_Multithreading_Rust_Multiprocessing_Threadpool_Fibers - Fatal编程技术网

Multithreading 为什么我的未来不能最大化CPU?

Multithreading 为什么我的未来不能最大化CPU?,multithreading,rust,multiprocessing,threadpool,fibers,Multithreading,Rust,Multiprocessing,Threadpool,Fibers,我正在创建几百个下载相同文件的请求(这是一个玩具示例)。当我使用Go运行等效逻辑时,我得到了200%的CPU使用率,并在约5秒钟内返回,其中包含800个请求。在只有100个请求的Rust中,它需要将近5秒的时间,产生16个操作系统线程,CPU利用率为37% 为什么会有这样的差异 据我所知,如果我有一个CpuPool管理Futures跨N内核,这就是Go runtime/goroutine组合在功能上所做的,只是通过光纤而不是未来 从perf数据来看,尽管使用了ThreadPoolExecutor

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

为什么会有这样的差异

据我所知,如果我有一个
CpuPool
管理
Future
s跨N内核,这就是Go runtime/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();
    }
}
extern板条箱卷曲;
外部板条箱纤维;
外部板条箱期货;
外部板条箱期货和cpupool;
使用std::io::{Write,BufWriter};
使用curl::easy::easy;
使用期货::期货::*;
使用std::fs::File;
使用futures\u cpupool::cpupool;
fn生成文件(x:i32,数据:&mut Vec){
让f=File::create(format!(“/data/{}.txt”,x)).expect(“无法打开文件”);
让mut writer=BufWriter::new(&f);
writer.write_all(data.as_mut_slice()).unwrap();
}
fn collect_请求(x:i32,url:&str)->结果{
让mut data=Vec::new();
让mut easy=easy::new();
easy.url(url.unwrap();
{
让mut transfer=easy.transfer();
转移
.write|u函数(|d|{
数据。从_切片(d)扩展_;
好的(d.len())
})
.unwrap();
transfer.perform().unwrap();
}
生成_文件(x和mut数据);
Ok(x)
}
fn main(){
让url=”https://en.wikipedia.org/wiki/Immanuel_Kant";
让pool=CpuPool::new(16);
让输出为:Vec=(0..100)
.into_iter()
.map(| ind |{
池。产卵(移动){
let output=collect_请求(ind,url);
输出
})
})
.收集();
//println!(“{:?}”,output_futures.Item());
对于我来说,在未来的输出{
i、 等待();
}
}

据我所知,如果我有一个
CpuPool
管理
Future
s跨N内核,这就是Go runtime/goroutine组合在功能上所做的,只是通过光纤而不是未来

这是不对的。我的重点是:

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

下载文件不是CPU绑定的,而是IO绑定的。您所做的只是启动多个线程,然后让每个线程在等待IO完成时阻塞


取而代之的是使用,它使curl库适应
未来的
抽象。然后可以完全删除线程池。这将大大提高您的吞吐量。

您是否使用--release标志编译和运行程序?@Shepmaster yes,优化级别为3Thanks!大部分开销不是在等待网络吗?因此,如果我已经为每个请求生成了未来,那么在响应可用并且我可以写入文件之前,它不应该阻塞吗?tokio通常适合于其他io绑定任务,如写入许多文件等吗?@Maximus12793不是等待网络的大部分开销——是的,这就是为什么我说“下载文件是[…]io绑定的”。它不应该阻塞吗?是的,除非您执行了阻塞调用(
.perform()
)。是的,我很确定这就是为什么它被称为tokio,而AFAIK是tokio存在的全部原因。就像写很多文件一样——遗憾的是,有很多。