我应该分割我的异步调用块根据cpu的数量

Should i split my async calls into chunks according to the number of CPUs?

本文关键字:cpu 分割 我的 异步 调用 我应该      更新时间:2023-10-16

在一台8处理器的机器上考虑这个脚本:

int parallel_function(int i){
    system(some_complex_and_long_call);
    return i;
}
int main() {
    // Parallel run
    std::vector<std::future<int>> futures;
    for(int i = 30; i > 0; i--) {
        futures.push_back (std::async(std::launch::async, parallel_function, i));
    }
    std::cout << "Stuff submitted" << std::endl;
    for(auto &e : futures) {
        std::cout << e.get() << std::endl;
    }
return 0;
}

它将在异步中产生30个系统调用,但是我只有8个处理器,每个系统调用可以(我猜应该)使用单个处理器的100%。

是一次只运行8个调用(甚至7个,并留下处理器空闲)更好,还是没关系,我可以调用尽可能多的。哪个跑得更快,为什么?

另一个侧面问题:我可以异步调用void函数,还是函数必须返回一些东西?

这取决于std:async的实现。

如果some_complex_and_long_call确实是CPU绑定任务,那么将线程数作为(逻辑)内核的数量似乎是合理的。

GCC实际上为每个std::async调用生成一个线程,因此您可能不想过多地使用async的GCC版本。线程的创建、调度和销毁是非常昂贵的,而且上下文切换会降低性能。在这种情况下,我建议你找到一个线程池实现(github上有很多),并使用线程池代替async

Clang和vc++在调用std::async时都在后台使用线程池,所以如果你正在使用这些编译器,生成尽可能多的async,底层实现将为你照顾线程创建。

另一个侧面问题:我可以在异步中调用void函数吗函数必须返回什么?

是的,这是可能的。在本例中,std::async将返回std::future<void>

一般来说每个物理核心一个线程可能是最好的,如果线程是cpu限制的,并且原则上每个线程一个任务可以最大限度地减少管理任务而不是执行实际工作的时间。

这假设您的任务(异步parallel_function调用)都需要大约相同的时间来完成。如果不是这种情况,您需要更多的任务来保持第一个完成的核心(s)忙碌。

如果它需要一个月的时间来运行(这是应该在问题中的相关信息),我怀疑24个可避免的同步操作会有很大的不同。

如果你的调度程序做了更多的上下文切换,它真的可能会减慢一切,但我不知道你的平台,或者是不是这样。


看到上面所有的if 和手势了吗?它们翻译成:

tl;博士 。也许吧。这取决于很多因素。为什么不试试看看呢?不管网上怎么说,这是唯一确定的方法。