Загальний підхід до використання декількох ядер, відверто кажучи, просто неправдивий. Поділ ваших підсистем на різні потоки дійсно розділить частину роботи на декілька ядер, але це має деякі основні проблеми. По-перше, з цим дуже важко працювати. Хто хоче розібратися із замками та синхронізацією, спілкуванням та іншим предметом, коли натомість він може просто писати прямий візуалізацію чи фізичний код? По-друге, підхід насправді не збільшує масштаб. У кращому випадку це дозволить вам скористатися, можливо, трьома-чотирма ядрами, і це якщо ви дійсно знаєте, що робите. У грі є лише стільки підсистем, а таких ще менше, що займають великі шматки часу процесора. Є кілька хороших альтернатив, які я знаю.
Один - мати основний потік разом з робочою ниткою для кожного додаткового процесора. Незалежно від підсистеми, основний потік делегує окремі завдання робочим потокам через якусь чергу (и); ці завдання також можуть створювати ще й інші завдання. Єдине призначення робочих ниток - це кожне захоплення завдань із черги по черзі та їх виконання. Найголовніше, однак, що як тільки нитка потребує результату завдання, якщо завдання виконано, воно може отримати результат, а якщо ні, то можна сміливо видалити завдання з черги та йти вперед і виконувати це сама задача. Тобто, не всі завдання в кінцевому підсумку будуть заплановані паралельно один одному. Мати більше завдань, ніж можна виконати паралельно, це добреріч у цьому випадку; це означає, що, ймовірно, збільшується масштаб, оскільки ви додаєте більше ядер. Одним із недоліків цього є те, що для розробки пристойної черги та робочого циклу потрібна велика робота, якщо ви не маєте доступу до бібліотеки чи мови виконання, які вже надають це для вас. Найважче - переконатися, що ваші завдання справді відокремлені та захищені від ниток, і переконайтеся, що ваші завдання знаходяться в щасливій середині між грубозернистим і дрібнозернистим.
Інша альтернатива потокам підсистеми - це паралелізація кожної підсистеми ізольовано. Тобто, замість того, щоб запускати візуалізацію та фізику у власних потоках, запишіть підсистему «фізика», щоб використати всі ваші ядра відразу, напишіть підсистему візуалізації, щоб використати всі ваші ядра відразу, а потім дві системи просто запускаються послідовно (або перемежовуються, залежно від інших аспектів вашої архітектури гри). Наприклад, у підсистемі фізики ви можете взяти всі точкові маси в грі, розділити їх між вашими ядрами, а потім одразу оновити всі ядра. Після цього кожне ядро може працювати над вашими даними у вузьких циклах із хорошою локальністю. Цей паралелізм стилю блокування схожий з тим, що робить GPU. Найважче тут - переконатися, що ви ділите свою роботу на дрібнозернисті шматки, такі, що розподіляють її рівномірнофактично призводить до рівного обсягу роботи у всіх процесорах.
Однак іноді просто простіше, через політику, існуючий код чи інші розчарувальні обставини, дати кожній підсистемі нитку. У такому випадку краще уникати створення більшої кількості потоків ОС, ніж ядер для великого навантаження процесора (якщо у вас є час виконання з легкими потоками, які просто зрівноважуються між вашими ядрами, це не так вже й багато). Також уникайте надмірного спілкування. Одна приємна хитрість - спробувати трубопровід; кожна основна підсистема може одночасно працювати над іншим ігровим станом. Трубопровідна робота знижує кількість необхідної комунікації між вашими підсистемами, оскільки не всі вони потребують доступу до одних і тих же даних одночасно, а також можуть звести нанівець частину шкоди, заподіяної вузькими місцями. Наприклад, якщо ваша фізична підсистема має тенденцію тривати довгий час, і ваша підсистема візуалізації закінчується завжди її чекаючи, ваша абсолютна частота кадрів може бути вищою, якщо ви запустите фізичну підсистему для наступного кадру, поки підсистема візуалізації все ще працює на попередній каркас. Насправді, якщо у вас є такі вузькі місця і ви не можете їх усунути будь-яким іншим способом, конвеєрна трубопровід може бути найбільш законною причиною турбуватися з потоками підсистеми.