Каковы издержки создания процесса в Windows?

Я продолжаю слышать, что создание нового процесса в Windows очень дорого. Но я не могу найти точные цифры. Есть ли приблизительное количество циклов? Сколько миллисекунд на 2-ГГц двухъядерном процессоре?

Я написал тестовую программу на Python и измерил 5 мс на процесс, но я не знаю, какая из этих дополнительных затрат связана с Python. Я не очень догадываюсь.

 assylias23 мая 2012 г., 00:24
Связанное обсуждение (но не ответ):stackoverflow.com/questions/47845/…
 0xC0000022L23 мая 2012 г., 00:22
В наши дни циклы не имеют такого же значения для процессоров, как раньше. У вас будет по крайней мере один переход в режим ядра, потому что и потоки, и процессы являются объектами ядра. Кроме того, это также будет зависеть от версии Windows (учитывая Shims).
 Hans Passant23 мая 2012 г., 01:20
Это высоко по сравнению с операционными системами Unix. Windows NT всегда поддерживала потоки с самого первого дня, Unix необходимо было реализовать многопроцессорность с процессами и приобретенными потоками согласованным образом примерно в 1997 году. Многообработка была задолго до этого. Вызов fork () был / есть ядром для выделения другого процесса. С оптимизацией, что она не создает совершенно новый процесс с нуля, поэтому может использовать преимущества существующего отображения виртуальной памяти. Windows создает процесс полностью с нуля.
 Harry Johnston23 мая 2012 г., 00:39
Вы можете получить представление о масштабе этого, используя Process Monitor (доступный на веб-сайте MS) и наблюдая за запуском нового процесса. Естьthousands файлов и операций реестра, имеющих место.
 0xC0000022L23 мая 2012 г., 00:47
Потому что большая часть времени создания процесса на Unixoid системахfork с последующимexec, который также имеет совершенно другую семантику. Это та же самая причина, по которой Apache предпочитает потоки в Windows, в то время какfork предпочтительнее в Linux. Это просто способ, которым система была спроектирована, и нужно знать свои инструменты.

Ответы на вопрос(1)

Решение Вопроса

Интересный вопрос!

Как сказано выше, накладные расходы высоки. Из любопытства, если вы быстро написали небольшой тест, чтобы понять, сколько времени занимает создание потока и процесса и как эти времена связаны.

#include <windows.h>
#include <stdio.h>
#include <conio.h>

#define MIN   0
#define AVG   1
#define MAX   2

DWORD WINAPI thread(LPVOID lpvData)
{
    return (0);
}

int main()
{
    BOOL result;
    int iteration;
    int i;
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    DWORD tStart;
    DWORD tEllapsed;
    double tCall;
    int spawnCount;
    HANDLE hThread;
    DWORD threadId;
    double ratio;
    double statCreateProcess[3];
    double statCreateThread[3];


    for (iteration = 0; iteration < 16; iteration++)
    {
        /*
        **  Measure creation time of process
        */
        tEllapsed = 0;
        spawnCount = 0;
        for (i = 0; i < 100; i++)
        {
            ZeroMemory(&si, sizeof(si));
            si.cb = sizeof(si);
            ZeroMemory(&pi, sizeof(pi));

            tStart = GetTickCount();
            result = CreateProcess(NULL,
                                   "cmd.exe",
                                   NULL,
                                   NULL,
                                   FALSE,
                                   NORMAL_PRIORITY_CLASS,
                                   NULL,
                                   NULL,
                                   &si,
                                   &pi);

            if (result != FALSE)
            {
                tEllapsed += GetTickCount() - tStart;
                spawnCount++;

                // clean up...
                TerminateProcess(pi.hProcess, 0);
                CloseHandle(pi.hThread);
                CloseHandle(pi.hProcess);
            }
        }
        tCall = tEllapsed / (double)spawnCount;
        printf("average creation time of process: %0.3fms\n", tCall);

        // track statistics...
        if (iteration > 0)
        {
            if (statCreateProcess[MIN] > tCall)
                statCreateProcess[MIN] = tCall;
            statCreateProcess[AVG] += tCall;
            if (statCreateProcess[MAX] < tCall)
                statCreateProcess[MAX] = tCall;
        }
        else
        {
            statCreateProcess[MIN] = tCall;
            statCreateProcess[AVG] = tCall;
            statCreateProcess[MAX] = tCall;
        }


        /* measure creation time of thread */
        spawnCount = 0;
        tStart = GetTickCount();
        for (i = 0; i < 5000; i++)
        {           
            hThread = CreateThread(NULL,
                                   0,
                                   thread,
                                   NULL,
                                   0,
                                   &threadId);
            if (hThread != NULL)
            {
                spawnCount++;

                // clean up...
                CloseHandle(hThread);
            }
        }
        tEllapsed = GetTickCount() - tStart;
        tCall = tEllapsed / (double)spawnCount;
        printf("average creation time of thread: %0.3fms\n", tCall);

        // track statistics...
        if (iteration > 0)
        {
            if (statCreateThread[MIN] > tCall)
                statCreateThread[MIN] = tCall;
            statCreateThread[AVG] += tCall;
            if (statCreateThread[MAX] < tCall)
                statCreateThread[MAX] = tCall;
        }
        else
        {
            statCreateThread[MIN] = tCall;
            statCreateThread[AVG] = tCall;
            statCreateThread[MAX] = tCall;
        }
    } /* for (iteration = ...) */

    statCreateProcess[AVG] /= iteration;
    statCreateThread[AVG] /= iteration;

    printf("\n\n--- CreateProcess(..) ---\n");
    printf("minimum execution time ...: %0.3fms\n", statCreateProcess[MIN]);
    printf("average execution time ...: %0.3fms\n", statCreateProcess[AVG]);
    printf("maximum execution time ...: %0.3fms\n", statCreateProcess[MAX]);
    printf("\n--- CreateThread(..) ---\n");
    printf("minimum execution time ...: %0.3fms\n", statCreateThread[MIN]);
    printf("average execution time ...: %0.3fms\n", statCreateThread[AVG]);
    printf("maximum execution time ...: %0.3fms\n", statCreateThread[MAX]);

    ratio = statCreateProcess[AVG] / statCreateThread[AVG];
    printf("\n\nratio: %0.3f\n\n", ratio);

    getch();
    return (0);
}

Я сделал несколько запусков на моем компьютере (i5 3,2 ГГц; Windows 7), и значения довольно постоянны, если антивирусное приложение выключено и тест запускается из-за пределов Visual Studio:

--- CreateProcess(..) ---
minimum execution time ...: 11.860ms
average execution time ...: 12.756ms
maximum execution time ...: 14.980ms

--- CreateThread(..) ---
minimum execution time ...: 0.034ms
average execution time ...: 0.037ms
maximum execution time ...: 0.044ms


ratio: 342.565

Как и ожидалось, вариация CreateProcess (..) больше, так как задействовано больше системных вызовов и вероятность прерывания другим потоком выше. Помните, что время для создания потока еще короче, поскольку измерение времени включает в себя весь цикл управления (в противном случае GetTickCount (..) будет слишком неточным для измерения времени).

Другой тест на виртуальном ПК под управлением Windows XP (работающий на той же машине, что и упомянутый выше) дал следующие значения:

--- CreateProcess(..) ---
minimum execution time ...: 22.630ms
average execution time ...: 24.666ms
maximum execution time ...: 27.340ms

--- CreateThread(..) ---
minimum execution time ...: 0.076ms
average execution time ...: 0.086ms
maximum execution time ...: 0.100ms


ratio: 287.982

Интересно, что соотношение среднего времени выполнения CreateProcess (..) и CreateThread (..) довольно близко.

Было бы интересно увидеть значения других машин и версий Windows. Я не удивлюсь, если соотношение примерно 300 будет одинаковым на разных машинах и версиях Windows.

Итак, давайте сделаем вывод: CreateProcess (..)much  медленнее, чем CreateThread (..) в Windows. Но на самом деле я шокирован тем, насколько медленнее это на самом деле ...

 08 июн. 2018 г., 19:38
Сколько из этого времени фактические накладные расходы дискового ввода-вывода? Какой тип диска был в тестовых системах? Как сравнить результаты теста, если вы запускаете действительно простой исполняемый файл Windows, который ссылается только на kernel32.dll?
 japreiss23 окт. 2014 г., 23:01
Хороший ответ! Вы получите какой-то значок за ответ на этот двухлетний вопрос!
 08 июн. 2018 г., 22:19
@IInspectable Ну, просто попробуй. Я предполагаю, что издержки дискового ввода-вывода не так уж и велики, так как исполняемый файл находился внутри дискового кэша во время моих повторных попыток. Я не удивлюсь, если результаты не так сильно отличаются. Как вы видите, я проверил это на своем ПК и на виртуальном ПК, и это соотношение очень близко ... дайте мне знать ваши результаты.

Ваш ответ на вопрос