Связь между временем выполнения потока, переключением контекста процессора и производительностью

Я провел эксперимент, чтобы смоделировать то, что произошло в нашем серверном коде, я запустил 1024 потока, и каждый поток выполняет системный вызов, для завершения выполнения на моей машине требуется около 2,8 с. Затем я добавляю usleep(1000000) в функцию каждого потока, время выполнения увеличивается до 16 секунд, а время уменьшается до 8 секунд, когда я запускаю ту же программу во второй раз. Я предполагаю, что это может быть вызвано кэшем процессора и переключением контекста процессора, но я не совсем уверен, как это объяснить.

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

Я приложил тестовый код здесь, большое спасибо за вашу помощь.

//largetest.cc
#include "local.h"
#include <time.h>
#include <thread>
#include <string>
#include "unistd.h"

using namespace std;

#define BILLION 1000000000L

int main()
{

    struct timespec start, end;
    double diff;

    clock_gettime(CLOCK_REALTIME, &start);

    int i = 0;
    int reqNum = 1024;

    for (i = 0; i < reqNum; i++)
    {
        string command = string("echo abc");
        thread{localTaskStart, command}.detach();
    }

    while (1)
    {
        if ((localFinishNum) == reqNum)
        {
            break;
        }
        else
        {
            usleep(1000000);
        }
        printf("curr num %d\n", localFinishNum);
    }

    clock_gettime(CLOCK_REALTIME, &end); /* mark the end time */
    diff = (end.tv_sec - start.tv_sec) * 1.0 + (end.tv_nsec - start.tv_nsec) * 1.0 / BILLION;
    printf("debug for running time = (%lf) second\n", diff);

    return 0;
}
//local.cc
#include "time.h"
#include "stdlib.h"
#include "stdio.h"
#include "local.h"
#include "unistd.h"
#include <string>
#include <mutex>

using namespace std;

mutex testNotifiedNumMtx;
int localFinishNum = 0;

int localTaskStart(string batchPath)
{

    char command[200];

    sprintf(command, "%s", batchPath.data());

    usleep(1000000);

    system(command);

    testNotifiedNumMtx.lock();
    localFinishNum++;
    testNotifiedNumMtx.unlock();

    return 0;
}

//local.h


#ifndef local_h
#define local_h

#include <string>

using namespace std;

int localTaskStart( string batchPath);

extern int localFinishNum;
#endif

1 ответ

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

На самом деле, программа может даже не завершиться, если вы скомпилируете ее в оптимизированном режиме, если компилятор решит поставить localFinishNum в реестре (вместо того, чтобы всегда загружать его из памяти).

Другие вопросы по тегам