Я хочу знать время, необходимое для выполнения метода в C ++ 11 std :: thread (или std :: async) по сравнению с прямым выполнением.Я знаю, что пулы потоков могут значительно сократить или даже полностью избежать этих издержек.Но я все еще хотел бы получить лучшее представление о числах.Я хотел бы знать примерно, за какую вычислительную стоимость окупается создание потока, и за какую цену окупается пул.
Я сам реализовал простой тест, который сводится к:
void PayloadFunction(double* aInnerRuntime, const size_t aNumPayloadRounds) {
double vComputeValue = 3.14159;
auto vInnerStart = std::chrono::high_resolution_clock::now();
for (size_t vIdx = 0; vIdx < aNumPayloadRounds; ++vIdx) {
vComputeValue = std::exp2(std::log1p(std::cbrt(std::sqrt(std::pow(vComputeValue, 3.14152)))));
}
auto vInnerEnd = std::chrono::high_resolution_clock::now();
*aInnerRuntime += static_cast<std::chrono::duration<double, std::micro>>(vInnerEnd - vInnerStart).count();
volatile double vResult = vComputeValue;
}
int main() {
double vInnerRuntime = 0.0;
double vOuterRuntime = 0.0;
auto vStart = std::chrono::high_resolution_clock::now();
for (size_t vIdx = 0; vIdx < 10000; ++vIdx) {
std::thread vThread(PayloadFunction, &vInnerRuntime, cNumPayloadRounds);
vThread.join();
}
auto vEnd = std::chrono::high_resolution_clock::now();
vOuterRuntime = static_cast<std::chrono::duration<double, std::micro>>(vEnd - vStart).count();
// normalize away the robustness iterations:
vInnerRuntime /= static_cast<double>(cNumRobustnessIterations);
vOuterRuntime /= static_cast<double>(cNumRobustnessIterations);
const double vThreadCreationCost = vOuterRuntime - vInnerRuntime;
}
Это работает довольно хорошо, и я могу получить типичные затраты на создание потоков ~ 20-80 микросекунд (нас) в Ubuntu 18.04 с современным Core i7-6700K.Во-первых, это дешево по сравнению с моими ожиданиями!
Но теперь возникает любопытная часть: накладные расходы на потоки, кажется, зависят (очень воспроизводимо) от фактического времени, потраченного на метод полезной нагрузки!Это не имеет смысла для меня.Но это воспроизводимо на шести разных аппаратных машинах с различными версиями Ubuntu и CentOS!
- Если я потрачу от 1 до 100 мкс внутри
PayloadFunction
, типичная стоимость создания потока составляет около 20 долл. - Когда я увеличиваю время, потраченное в
PayloadFunction
до 100-1000us, стоимость создания потока увеличивается примерно до 40us. - Дальнейшее увеличение до более чем 10000us в
PayloadFunction
снова увеличивает стоимость создания потока.примерно до 80 мкс.
Я не пошел на большие диапазоны, но я ясно вижу соотношение между временем полезной нагрузки и накладными расходами потоков (как вычислено выше).Поскольку я не могу объяснить это поведение, я предполагаю, что должна быть ловушка.Возможно ли, что мои измерения времени настолько неточны?Или CPU Turbo может вызывать разные временные характеристики в зависимости от более высокой или более низкой нагрузки?Может кто-нибудь пролить свет?
Вот случайный пример времени, которое я получаю.Числа являются репрезентативными для шаблона, описанного выше.Одна и та же картина наблюдается на многих компьютерных аппаратных средствах (различные процессоры Intel и AMD) и разновидностях Linux (Ubuntu 14.04, 16.04, 18.04, CentOS 6.9 и CentOS 7.4):
payload runtime 0.3 us., thread overhead 31.3 us.
payload runtime 0.6 us., thread overhead 32.3 us.
payload runtime 2.5 us., thread overhead 18.0 us.
payload runtime 1.9 us., thread overhead 21.2 us.
payload runtime 2.5 us., thread overhead 25.6 us.
payload runtime 5.2 us., thread overhead 21.4 us.
payload runtime 8.7 us., thread overhead 16.6 us.
payload runtime 18.5 us., thread overhead 17.6 us.
payload runtime 36.1 us., thread overhead 17.7 us.
payload runtime 73.4 us., thread overhead 22.2 us.
payload runtime 134.9 us., thread overhead 19.6 us.
payload runtime 272.6 us., thread overhead 44.8 us.
payload runtime 543.4 us., thread overhead 65.9 us.
payload runtime 1045.0 us., thread overhead 70.3 us.
payload runtime 2082.2 us., thread overhead 69.9 us.
payload runtime 4160.9 us., thread overhead 76.0 us.
payload runtime 8292.5 us., thread overhead 79.2 us.
payload runtime 16523.0 us., thread overhead 86.9 us.
payload runtime 33017.6 us., thread overhead 85.3 us.
payload runtime 66242.0 us., thread overhead 76.4 us.
payload runtime 132382.4 us., thread overhead 69.1 us.