Какое влияние (время) может оказать отдельный оператор if в узком цикле? - PullRequest
4 голосов
/ 01 декабря 2010

Я работаю над приложением на C ++, которое использует узкий цикл для перебора состояний в нашем FSM .Прямо сейчас, из-за жесткой петли, он использует 100% CPU, и нашим клиентам это не нравится.Я хотел попробовать поставить sleep(1) в узкий цикл, чтобы ослабить его, но мы беспокоимся, что это заставит его слишком долго спать между состояниями для наших крупных клиентов (чьи состояния меняются очень быстро!)Я думал попробовать что-то вроде этого:

if(smallcustomer)
{
    sleep(1);
}

И smallcustomer будет определено где-то еще, когда программа запустится.Разве это утверждение «если» просто замедляет вещи так же сильно, как сон, и наносит ущерб своей цели?

Ответы [ 8 ]

7 голосов
/ 01 декабря 2010

Вы подразумеваете, что FSM не должен требовать 100% ЦП, что заставляет меня предположить, что вы тратите много времени, ничего не делая, кроме проверки, нужно ли переходить кследующее состояние или нет.Вы говорите, что беспокоитесь о том, чтобы «спать слишком долго» для крупных клиентов, а это значит, что вы обеспокоены тем, что какое-то событие будет пропущено: заполнение очереди, щелчок мыши, получение пакета, завершение дискового ввода-вывода, ключнажал, что угодно.Вы должны рефакторинг для асинхронного запуска этого события (или событий) вместо того, чтобы загружать процессор, ничего не делая в цикле.

2 голосов
/ 01 декабря 2010

Краткий ответ: Я подозреваю, что простое утверждение if () не сильно повредит. Однако золотым правилом оптимизации является тестовый тестовый тест.

Более длинный ответ: несколько более чистый (хотя и более сложный) подход состоял бы в том, чтобы перенести трудоемкую обработку FSM в отдельный / фоновый поток, возможно, с более низким приоритетом планирования. Это может дать вам лучшее из обоих миров: быстрая обработка при свободном процессоре и меньшая нагрузка на систему из-за более низкого приоритета.

Только мои 2 цента ...

1 голос
/ 01 декабря 2010

Предполагая, что ваш FSM работает как задумано, должна быть возможность объяснить пострадавшим клиентам, что незанятые процессоры не свидетельствуют о хорошо разработанной программе.Любой код, который никогда не достигнет состояния ожидания, будет использовать 100% ЦП в течение своего временного интервала.Во многих случаях это было бы выгодно.

То, что вы делаете, приведет к снижению производительности вашего приложения.Вы уверены, что это то, что вы хотите?

Если FSM чрезмерно зацикливается или постоянно истощает ресурсы других программ CPU, это другое обсуждение.В этом случае может помочь профилирование приложения для включения проверки и изменения целевого кода.

1 голос
/ 01 декабря 2010

Простой оператор if должен скомпилироваться с инструкцией (ами) сравнения и ветвления (на некоторых платформах вы получите одну, на других - две), которая будет выполняться очень быстро.

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

Если платформа поддерживает это, usleep даст вам более точный контроль зерна, чем sleep.

0 голосов
/ 01 декабря 2010

Ваш дизайн почти наверняка не так. Оживленное ожидание оправдано только во встроенных приложениях реального времени. Даже в этом случае, если ваш контроллер выполняет более чем одну вещь параллельно, вы будете реализовывать его с прерываниями, если это возможно.

Какой бы ни была ваша причина, вы можете вывести if из цикла. Вы можете использовать шаблоны для предотвращения копирования вставленного кода:

template<bool flag> void mysleep(){}
template<> void mysleep<true>() { sleep(1); }

template<bool flag> void myf() {
    for(;;) {
        // your loop goes here

        mysleep<flag>();
    }
}

void f() {
    smallcustomer ? myf<true>() : myf<false>();
}

Теперь звоните f();.

0 голосов
/ 01 декабря 2010

Если вас действительно беспокоят условные выражения, попробуйте это предложение для прогноза ветвления в GCC:

#define likely(x)       __builtin_expect((x),1)
#define unlikely(x)     __builtin_expect((x),0)

if(likely(smallcustomer))
{
    sleep(1);
}
0 голосов
/ 01 декабря 2010

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

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

Если вы действительно используете мягкое приложение реального времени, и оно использует 100% ЦП, это, вероятно, не означает, что вы должны пытаться сократить использование, но предоставить больше ЦП для его использования, потому что ввод опережает способность приложения идти в ногу. На самом деле масштабирование или уменьшение, вероятно, дешевле, чем повышение производительности кода, серверное оборудование обходится дешевле, чем время разработчиков.

0 голосов
/ 01 декабря 2010

Вы должны использовать более специфический инструмент синхронизации, чем просто sleep () - например, таймеры ожидания в Win32, хотя у меня нет эквивалента для Linux / Mac.Функции стиля Sleep () довольно печально известны своей ненадежностью.Лучше всего было бы, если бы вы могли позволить клиенту изменить период таймера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...