2017-03-01 153 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容器中可能更小。