我有大量(>>> 100K)的任务,具有非常高的延迟(分钟)和非常少的资源消耗。可能它们都可以并行执行,我正在考虑使用std::async
为每个任务生成一个未来。
我的问题是: std :: async将异步创建和执行的最大线程数是多少? (在Ubuntu 16-xx或CentOs 7.x上使用g ++ 6.x - x86_64)
对我来说,正确获取该数字非常重要,因为如果我没有足够的任务实际并行运行(等待),则延迟的累积成本会非常高。
为了得到答案,我首先检查了系统的功能:
bob@vb:~/programming/cxx/async$ ulimit -u
43735
bob@vb:~/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):
bob@vb:~/programming/cxx/async$ /usr/bin/time -f "%E" ./testAsync 100000
COUNT: 100000: ids.size(): 32748
0:03.29
然后我在foo
中取消注释睡眠线以增加2s的睡眠时间。结果时序与2到10K任务左右一致,但在某些时候,某些任务最终会共享相同的线程ID,并且每个额外任务的经过时间会增加2秒:
bob@vb:~/programming/cxx/async$ /usr/bin/time -f "%E" ./testAsync 10056
COUNT: 10056: ids.size(): 10056
0:02.24
bob@vb:~/programming/cxx/async$ /usr/bin/time -f "%E" ./testAsync 10057
COUNT: 10057: ids.size(): 10057
0:04.27
bob@vb:~/programming/cxx/async$ /usr/bin/time -f "%E" ./testAsync 10058
COUNT: 10058: ids.size(): 10057
0:06.28
bob@vb:~/programming/cxx/async$ ps -eT | wc -l
277
所以,看起来对于我的问题,在这个系统上,限制大约是10K。我检查了另一个系统,限制是4K的顺序。
我无法弄清楚:
答案 0 :(得分:0)
使用linux上的g ++,直截了当的答案似乎是“在pthread_create失败并返回EAGAIN之前可以创建的最大线程数”。该数字可以受到几个不同值的限制,man pthread_create
列出其中3个:
/proc/sys/kernel/threads-max
的值(分别为2061857和87470)/proc/sys/kernel/pid_max
(40960和32768 resp。) systemd
至少还有一个可能的限制,因为man logind.conf
表示:
UserTasksMax =设置每个用户可以同时运行的最大OS任务数。它控制每用户切片单元的TasksMax =设置,有关详细信息,请参阅systemd.resource-control(5)。默认为33%,与内核在主机上的默认值相等,为10813,但在OS容器中可能更小。