Я провел эксперимент, чтобы смоделировать то, что произошло в коде нашего сервера, я запустил 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
Чтение localFinishNum
также должны быть защищены мьютекс, в противном случае результаты непредсказуемы в зависимости от того, где (то есть, на каких ядрах) запланированы потоки, когда и как кэш-память становится недействительной и т. д.
На самом деле, программа может даже не завершиться, если вы скомпилируете ее в оптимизированном режиме, если компилятор решит поставить localFinishNum
в реестре (вместо того, чтобы всегда загружать его из памяти).
Других решений пока нет …