2017-03-01 158 views
0

我有大量(>> 100K)的任务,具有非常高的延迟(分钟)和非常少的资源消耗。可能他们都可以并行执行,我正在考虑使用std::async为每个任务生成一个未来。std :: async将异步创建和执行的最大线程数是多少?

我的问题是:什么是std :: async将异步创建和执行的线程的最大数量是多少? (在Ubuntu 16-xx或CentOs 7.x-x86_64上使用g ++ 6.x)

对我来说很重要,因为如果我没有足够的任务实际运行(等待)并行累积延迟成本将非常高。

要得到一个答案,我开始检查系统的功能:

[email protected]:~/programming/cxx/async$ ulimit -u 
43735 
[email protected]:~/programming/cxx/async$ cat /proc/sys/kernel/threads-max 
87470 

根据这些数字,我期待能在运行(主要是等待)的43K线程为了得到在平行下。为了验证这一点,我写了下面的程序检查不同的线程ID的数量,并呼吁100K std::async一个空任务所需的时间:

#include <thread> 
#include <future> 
#include <iostream> 
#include <vector> 
#include <algorithm> 
#include <chrono> 
#include <string> 

std::thread::id foo() 
{ 
    using namespace std::chrono_literals; 
    //std::this_thread::sleep_for(2s); 
    return std::this_thread::get_id(); 
} 

int main(int argc, char **argv) 
{ 
    if (2 != argc) exit(1); 
    const size_t COUNT = std::stoi(argv[1]); 
    std::vector<decltype(std::async(foo))> futures; 
    futures.reserve(COUNT); 
    while (futures.capacity() != futures.size()) 
    { 
     futures.push_back(std::async(foo)); 
    } 
    std::vector<std::thread::id> ids; 
    ids.reserve(futures.size()); 
    for (auto &f: futures) 
    { 
     ids.push_back(f.get()); 
    } 
    std::sort(ids.begin(), ids.end()); 
    const auto end = std::unique(ids.begin(), ids.end()); 
    ids.erase(end, ids.end()); 
    std:: cerr << "COUNT: " << COUNT << ": ids.size(): " << ids.size() << std::endl; 
} 

的时间是罚款,但不同的线程ID的数量是多少低于预期(的32748,而不是43735):

[email protected]:~/programming/cxx/async$ /usr/bin/time -f "%E" ./testAsync 100000 
COUNT: 100000: ids.size(): 32748 
0:03.29 

然后我取消注释中foo睡眠线增加一个2秒的睡眠时间。得到的时序与2S高达10K任务或如此一致,但超出了一些点,一些任务最终上涨2秒,每增加任务共享相同的线程ID和经过时间的增加:

[email protected]:~/programming/cxx/async$ /usr/bin/time -f "%E" ./testAsync 10056 
COUNT: 10056: ids.size(): 10056 
0:02.24 
[email protected]:~/programming/cxx/async$ /usr/bin/time -f "%E" ./testAsync 10057 
COUNT: 10057: ids.size(): 10057 
0:04.27 
[email protected]:~/programming/cxx/async$ /usr/bin/time -f "%E" ./testAsync 10058 
COUNT: 10058: ids.size(): 10057 
0:06.28 
[email protected]:~/programming/cxx/async$ ps -eT | wc -l 
277 

所以,看起来对于我的问题,在这个系统上,限制在10K左右。我检查了另一个系统,限制在4K的数量级。

我想不通:

  • 为什么这些值是如此之小
  • 如何在Linux系统
+0

那么,每个线程都需要从操作系统获取一些资源。线程堆栈的典型默认大小为8MB,因此需要总共_thread-count * 8MB_的DRAM。这不仅是关于启动更多的线程,你需要有资源...阅读[这里](http://stackoverflow.com/questions/25814365/when-to-use-stdasync-vs-stdthreads)了。 – Arash

+0

没有几乎同样荒谬的处理核心的荒谬数量的任务并不是那么有用。这些线程将花费大部分时间来争取访问处理器。考虑使用线程池。 – user4581301

+0

@arash感谢您的链接。关于DRAM的使用,即使默认的线程堆栈大小为8MB,我也会认为这是虚拟内存,并且实际需要的DRAM数量是线程实际使用的数量(四舍五入到页面大小)。我错了吗? –

回答

0

随着G ++的规格预测这些值,简单答案似乎是“在pthread_create失败并返回EAGAIN之前可以创建的最大线程数”。

  • RLIMIT_NPROC:软资源限制(4096我的CentOS 7服务器和43735在我的Ubuntu/VirtualBox的笔记本电脑)
  • /proc/sys/kernel/threads-max值,这个数字可以由几个不同的价值观和man pthread_create列出其中3被限制(2061857和87470)
  • /proc/sys/kernel/pid_max(40960和32768 resp。)

有由systemd施加至少一个其他可能的限制,如man logind.conf表示:

UserTasksMax =设置的每个用户可以同时运行OS任务的最大数目。这将控制每个用户切片单元的TasksMax =设置,有关详细信息,请参阅systemd.resource-control(5)。默认为33%,相当于主机上内核默认的10813,但在OS容器中可能更小。