How long does thread creation and termination take under Windows?

前端 未结 3 675
长情又很酷
长情又很酷 2020-12-15 18:31

I\'ve split a complex array processing task into a number of threads to take advantage of multi-core processing and am seeing great benefits. Currently, at the start of the

3条回答
  •  暗喜
    暗喜 (楼主)
    2020-12-15 19:03

    I was curious about the modern Windows scheduler, so I wrote another test app. I made my best attempt at measuring thread stop time by optionally spinning up a watching thread.

    // Tested on Windows 10 v1903 with E5-1660 v3 @ 3.00GHz, 8 Core(s), 16 Logical Processor(s)
    // Times are (min, average, max) in milliseconds.
    
    threads: 100, iterations: 1, testStop: true
    Start(0.1083, 5.3665, 13.7103) - Stop(0.0341, 1.5122, 11.0660)
    
    threads: 32, iterations: 3, testStop: true
    Start(0.1349, 1.6423, 3.5561) - Stop(0.0396, 0.2877, 3.5195)
    Start(0.1093, 1.4992, 3.3982) - Stop(0.0351, 0.2734, 2.0384)
    Start(0.1159, 1.5345, 3.5754) - Stop(0.0378, 0.4938, 3.2216)
    
    threads: 4, iterations: 3, testStop: true
    Start(0.2066, 0.3553, 0.4598) - Stop(0.0410, 0.1534, 0.4630)
    Start(0.2769, 0.3740, 0.4994) - Stop(0.0414, 0.1028, 0.2581)
    Start(0.2342, 0.3602, 0.5650) - Stop(0.0497, 0.2199, 0.3620)
    
    threads: 4, iterations: 3, testStop: false
    Start(0.1698, 0.2492, 0.3713)
    Start(0.1473, 0.2477, 0.4103)
    Start(0.1756, 0.2909, 0.4295)
    
    threads: 1, iterations: 10, testStop: false
    Start(0.1910, 0.1910, 0.1910)
    Start(0.1685, 0.1685, 0.1685)
    Start(0.1564, 0.1564, 0.1564)
    Start(0.1504, 0.1504, 0.1504)
    Start(0.1389, 0.1389, 0.1389)
    Start(0.1234, 0.1234, 0.1234)
    Start(0.1550, 0.1550, 0.1550)
    Start(0.2800, 0.2800, 0.2800)
    Start(0.1587, 0.1587, 0.1587)
    Start(0.1877, 0.1877, 0.1877)
    

    Source:

    #include 
    #include 
    #include 
    #include 
    #include 
    
    using namespace std::chrono;
    
    struct Test
    {
        HANDLE Thread = { 0 };
        time_point Creation;
        time_point Started;
        time_point Stopped;
    };
    
    DWORD __stdcall ThreadProc(void* lpParamater) {
        auto test = (Test*)lpParamater;
        test->Started = steady_clock::now();
        return 0;
    }
    
    DWORD __stdcall TestThreadsEnded(void* lpParamater) {
        auto& tests = *(std::vector*)lpParamater;
    
        std::size_t finished = 0;
        while (finished < tests.size())
        {
            for (auto& test : tests)
            {
                if (test.Thread != NULL && WaitForSingleObject(test.Thread, 0) == WAIT_OBJECT_0)
                {
                    test.Stopped = steady_clock::now();
                    test.Thread = NULL;
                    finished++;
                }
            }
        }
    
        return 0;
    }
    
    duration diff(time_point start, time_point stop)
    {
        return stop - start;
    }
    
    struct Stats
    {
        double min;
        double average;
        double max;
    };
    
    Stats stats(const std::vector& durations)
    {
        Stats stats = { 1000, 0, 0 };
    
        for (auto& duration : durations)
        {
            stats.min = duration < stats.min ? duration : stats.min;
            stats.max = duration > stats.max ? duration : stats.max;
            stats.average += duration;
        }
    
        stats.average /= durations.size();
    
        return stats;
    }
    
    void TestScheduler(const int threadCount, const int iterations, const bool testStop)
    {
        std::cout << "\nthreads: " << threadCount << ", iterations: " << iterations << ", testStop: " << (testStop ? "true" : "false") << "\n";
    
        for (auto i = 0; i < iterations; i++)
        {
            std::vector tests(threadCount);
            HANDLE testThreadsEnded = NULL;
    
            if (testStop)
            {
                testThreadsEnded = CreateThread(NULL, 0, TestThreadsEnded, (void*)& tests, 0, NULL);
            }
    
            for (auto& test : tests)
            {
                test.Creation = steady_clock::now();
                test.Thread = CreateThread(NULL, 0, ThreadProc, (void*)& test, 0, NULL);
            }
    
            if (testStop)
            {
                WaitForSingleObject(testThreadsEnded, INFINITE);
            }
            else
            {
                std::vector threads;
                for (auto& test : tests) threads.push_back(test.Thread);
                WaitForMultipleObjects((DWORD)threads.size(), threads.data(), TRUE, INFINITE);
            }
    
            std::vector startDurations;
            std::vector stopDurations;
            for (auto& test : tests)
            {
                startDurations.push_back(diff(test.Creation, test.Started).count());
                stopDurations.push_back(diff(test.Started, test.Stopped).count());
            }
    
            auto startStats = stats(startDurations);
            auto stopStats = stats(stopDurations);
    
            std::cout << std::fixed << std::setprecision(4);
            std::cout << "Start(" << startStats.min << ", " << startStats.average << ", " << startStats.max << ")";
            if (testStop)
            {
                std::cout << " - ";
                std::cout << "Stop(" << stopStats.min << ", " << stopStats.average << ", " << stopStats.max << ")";
            }
            std::cout << "\n";
        }
    }
    
    int main(void)
    {
        TestScheduler(100, 1, true);
        TestScheduler(32, 3, true);
        TestScheduler(4, 3, true);
        TestScheduler(4, 3, false);
        TestScheduler(1, 10, false);
        return 0;
    }
    

提交回复
热议问题