Просто тестирую две небольшие программы,
#include <thread>
int main()
{
for (int i = 0; i < 10000000; i++)
{
std::this_thread::yield();
}
return 0;
}
и:
#include <thread>
#include <chrono>
int main()
{
using namespace std::literals;
for (int i = 0; i < 10000000; i++)
{
std::this_thread::sleep_for(0s);
}
return 0;
}
Я получаю соответствующие тайминги в своей системе (Ubuntu 22.04 LTS, версия ядра 5.19.0-43-универсальная),
./a.out 0,33s user 1,36s system 99% cpu 1,687 total
и:
./a.out 0,14s user 0,00s system 99% cpu 0,148 total
Почему std::this_thread::yield() в 10 раз медленнее, чем std::this_thread::sleep_for(0s)?
Н.Б. Время одинаково для g++ и clang++.
редактировать: как указано в ответе, это оптимизация реализации STL, вызов sleep(0) на самом деле в 300 раз медленнее (50 мкс против 150 нс).





Быстро взглянем на источник для this_thread::sleep_for
template<typename _Rep, typename _Period>
inline void
sleep_for(const chrono::duration<_Rep, _Period>& __rtime)
{
if (__rtime <= __rtime.zero())
return;
...
Итак, sleep_for(0s) ничего не делает, на самом деле ваша тестовая программа использует 0,0 с системного времени, в основном пустой цикл, который полностью выполняется в пользовательском пространстве (на самом деле я подозреваю, что если вы скомпилируете с оптимизацией, он будет полностью удален)
С другой стороны, yield вызывает *sched_yield, который, в свою очередь, вызывает schedule() в пространстве ядра, таким образом, по крайней мере, выполняя некоторую логику, чтобы проверить, есть ли другой поток для планирования.
Я считаю, что ваши 0,33 секунды пользовательского пространства в основном накладные расходы на системные вызовы.
* Actually jumps to __libcpp_thread_yield which then calls sched_yield, at least on linux
Спасибо. Действительно, мы даже не выполняем системный вызов. К вашему сведению, кажется, что вызов sleep(0) из unistd.h намного медленнее.
Кроме того, после получения потока поток должен ждать, пока ОС снова не запланирует его для следующего запуска. Что также занимает (стенное) время
Это деталь реализации, но
sleep_for(x);обычно выполняет однуif (x>0)проверку, а затем ничего, если x равно нулю. В отличие от yield(), который, насколько я понимаю, фактически приостанавливает поток и возвращает управление ОС.