Производительность запуска многопоточной программы на одном ядре путем установки соответствия? - PullRequest
4 голосов
/ 23 сентября 2011

Вкратце:

При каких сценариях запуск многопоточного приложения на одном ядре может снизить производительность?

А как насчет настройки схожести многопоточного приложения на использование только одного ядра?

В общем:

Я пытаюсь запустить физику двумерного движка на нем.собственный поток.Это работает, и поначалу производительность казалась нормальной, но я решил сказать, что игра должна работать на скорости 10K FPS, а физика - на 120 FPS, зашел в диспетчер задач и установил сходство с тем, чтобы программа могла использовать только одно ядро.

FPS был на уровне ~ 1700, прежде чем устанавливать сродство к одному ядру, после этого он достигал ~ 70FPS.Я не ожидал такого снижения.Я сказал игре попробовать 300 фпс и физику 60 фпс.

То же самое произошло.

Я не задумывался об этом, поэтому я просто продолжил модифицировать двигатель.Я проверил это позже, после изменения кода рисования, 300 FPS, 60 FPS для физики.Со всеми разрешенными ядрами он прекрасно управлял 300FPS, а привязка к одноядерному FPS снизилась до 4. Теперь я знаю, что не может быть плохого запуска многопоточного приложения на одном ядре, или я не знаю, что происходит, когдавы устанавливаете сродство к одному ядру.

Это о том, как работает рендеринг / физика ...

Цикл запускается

Сбор ввода до тех пор, пока (1.0 / FPS) не будетпройдено.

Обновление вызова.

Блокировка мьютекса потока физики, потому что в игре будут использоваться данные физики, и я не хочу, чтобы движок обновлял что-либо, пока все в этом вызове обновления не завершится.

Обновите все в игре, что может посылать объект функции Draw (Содержит, что рисовать, где рисовать, как рисовать) в очередь Render.

Разблокировать мьютекс.

Renderer вызывает operator () для каждого объекта функции и удаляет их из очереди.

экран обновления.

цикл повторения.

цикл физического потока:

    ALLEGRO_TIMER* timer(al_create_timer(1.0f / 60.0f));
    double prevCount(0);

    al_start_timer(timer);
    while(true)
    {
        auto_mutex lock(m_mutex);

        if(m_shutdown)
            break;
        if (!m_allowedToStep)
            continue;
                    // Don't run too fast. This isn't final, just simple test code.
        if (!(al_get_timer_count(timer) > prevCount))
            continue;

        prevCount = al_get_timer_count(timer);

        m_world->Step(1.0f / 60.0f, 10, 10); 
        m_world->ClearForces();

    }

// Примечание: Auto mutex - это просто очень простой объект, который я создал, чтобы заблокировать мьютекс в конструкторе и разблокировать его в деструкторе.Я использую функции потоков Allegro 5.

Ответы [ 2 ]

7 голосов
/ 24 сентября 2011

При каких сценариях запуск многопоточного приложения на одном ядре может снизить производительность?

Как насчет настройки соответствия многопоточного приложения только одному ядру?

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

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

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

Но вы можете сделать его еще хуже.Спин-блокировка или любой другой цикл ожидания занятости абсолютно разрушит производительность.И должно быть понятно почему.Вы можете запускать только один поток за раз, поэтому, если вам нужен поток для ожидания какого-либо события, вы должны указать операционной системе немедленно перевести его в спящий режим, чтобы можно было запустить другой поток.

Если вместо этого выпросто сделайте некоторое «пока условие не выполнено, продолжайте цикл» занятый цикл, вы сохраняете поток работающим, даже если он не имеет ничего общего.Он будет продолжать цикл * до тех пор, пока ОС не решит, что время истекло, и не запланирует другой поток.(И если поток не блокируется чем-то, ему обычно разрешается запускаться более 10 миллисекунд за раз.)

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

И угадайте, что делает ваш код.

Как вы думаете, какой эффект от этих строк?

   if (!(al_get_timer_count(timer) > prevCount))
        continue;

ЗАПУСТИТЬ ПЕТЛЯ!Я ГОТОВ БЫТЬ ЕЩЕ?НЕТ?Затем снова бегите по петле.Готов ли я бежать сейчас?ВСЕ ЕЩЕ НЕТ?ЗАПУСТИТЕ ЦИКЛ ВНОВЬ ..... ..... 1026 *

Другими словами: «У меня сейчас ЦП, и я НИКОГДА НЕ УБУДУ!! "

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

Используйте мьютекс или какой-либо другой примитив синхронизации, или, если вы в порядке с более приблизительным периодом сна, основанным на времени, позвоните Sleep().

Но не надо, если вы хотите любой приличный уровень производительности, неограниченно загружайте процессор, если вы ожидаете, что другой поток выполнит некоторую обработку.

1 голос
/ 23 сентября 2011

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

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

Это действительно влияет на то, как вы смотрите на многопоточность, потому что когда Windows смотрит вокруг и видит многопоточное приложение,скажет "я буду обрабатывать это как 2 отдельные программы", поэтому он выделяет время для обеих.поэтому одно полностью не помешает другому выполнять вычисления.

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

...