Страницы

Поиск по вопросам

четверг, 9 января 2020 г.

Как избежать пустую нагрузку на процессор в цикле?

#cpp #sfml


Работая над меню игры, которая создаётся с помощью SFML, столкнулся с проблемой "пустой"
загрузки процессора в циклах, которые не высчитывают что-либо в прямом значении этого
слова, а просто ожидают каких-либо событий от пользователя и меняют состояние (выходят
из него или опускаются глубже во внутренние циклы) только тогда, когда что-то происходит,
а до тех пор выводят изображение на экран и тому подобное, тем самым нагружая процессор
на ~20-30%, хотя реально такие мощности не используются. 

Пытался это решить с помощью ожидания события (waitEvent), а не его "вылова" (pollEvent),
но это просто стопорило программу. Может быть как-то неправильно этим пользовался.

Да и не только в данном проекте столкнулся с подобным. В других так же, где были
аналогичные циклы.

Сам "скелет" подобного цикла выглядит примерно так:

while (window.isOpen())
{
    sf::Event event;
    while (window.pollEvent(event))
    {
        if (event.type == sf::Event::Closed)
            window.close();
    }

    window.clear();
    //window.draw(something);
    window.display();
}




Как решать подобные проблемы? Уместно ли будет использовать таймеры или функции типа
Sleep()? Какие технологии можно применять для оптимизации подобных ситуаций? 
    


Ответы

Ответ 1



У класса окна sf::Window имеется метод setFramerateLimit. Но он не гарантирует тот факт что частота кадров будет равна той, которую вы установили. Т.к. он все так же использует функцию sf::sleep. Ограничивает частоту кадров до максимальной фиксированной частоты. Если установлен лимит, окно будет использовать небольшую задержку после каждого вызова display(), чтобы гарантировать что текущий кадр длился достаточно долго, и соответствовать пределу частоты кадров. SFML будет пытаться соответствовать заданному пределу, насколько это возможно, но так как он внутренне использует sf::sleep, точность которого зависит от базовой ОС, результаты могут быть немного неточными (например, вы можете получить 65 кадров в секунду при запросе 60).

Ответ 2



Небольшое вступление. Процессор всегда загружен на 100%, даже если он ничего не делает. Если в диспетчере написано, что процессор загружен на 1%, это лишь значит, что процессор 99% времени работает в холостую, ожидая полезную нагрузку. У разных процессоров есть различные механизмы торможения. Одни процессоры могут полностью уснуть, ожидая прерывания на каком-нибудь порте, другие - предоставляют специализированные команды, которые понижают частоту камня в тех или иных условиях. Если вас интересует, как ограничивают скорость работы главного цикла (например, в играх), то там имеется несколько способов. Каждый со своими клопами. В простых случаях для снижения потока пустой информации через процессор можно использовать Sleep(1); или что-то аналогичное. В сложных стратегиях управления работой процессора можно усыплять процесс/поток с последующим пробуждением по событию + срабатыванию таймера ядра ОС. Важно понимать, что отрисовка и просчеты должны происходить независимо от факта поступления событий, потому что ваше окно может не получать никаких событий несколько секунд, а потом получит 1000 событий за 1 мс. Часто - и обработка событий, и просчеты, и отрисовка - должны происходить независимо. Иногда для каждого процесса используются сложные алгоритмы планирования и предсказания. Это делается для сглаживания поведения игры на различных устройствах.

Ответ 3



Решил данную проблему просто заменой внутреннего цикла обработки событий на условный оператор, который ожидает событие и потом его обрабатывает во вложенных операторах: sf::Event event; if (window.waitEvent(event)) { ... } Получается, что программа на данной строке будет просто ожидать любого события (нажатие клавиши, движение курсора мыши и тд) и дальнейшие итерации основного цикла будут происходить только тогда, когда происходит что-либо, без "пустой" нагрузки на процессор постоянными не контролируемыми итерациями. По сравнению с предыдущим вариантом, нагрузка снизилась до 1-2% без какой-либо потери функциональности.

Комментариев нет:

Отправить комментарий