Регулирование потоков в C#

Я создал игру в VS2010, используя VB .NET 4 на С#. Игра создает поток для каждого игрока и запускает код LUA, созданный игроками.

Каждый код LUA блокирует поток и должен завершаться только тогда, когда поток завершается (сценарий LUA должен содержать бесконечный цикл)

Я хочу ограничить использование ЦП, так как компьютер в настоящее время перегревается после работы со 100% ЦП в течение нескольких часов.

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

Любые идеи?

Спасибо!


person pcaston2    schedule 08.08.2012    source источник
comment
Можете ли вы сделать так, чтобы ваш код C-Sharp вызывал метод, который по сути является вашим основным циклом? Я не уверен, есть ли в LUA таймер с высоким разрешением (который, как я предполагаю, вы используете для своей игровой логики), но C-Sharp точно есть, поэтому ваш основной метод в LUA может принимать дельту между кадрами вместо вычислить его самостоятельно.   -  person Matthew    schedule 09.08.2012
comment
В настоящее время это работает так, что вся игровая логика выполняется в C-Sharp. потоки LUA могут получать информацию об игре и возвращать управляющую информацию в игру с помощью функций .NET, которые также можно вызывать в LUA (своего рода сопоставление функций). Я не уверен, что понимаю, о чем вы спрашиваете, это помогает?   -  person pcaston2    schedule 09.08.2012
comment
У меня сложилось впечатление, что LUA будет выполнять большую часть игровой логики. Что добавляет LUA, если C-Sharp выполняет логику?   -  person Matthew    schedule 09.08.2012
comment
Думайте о LUA как о контроллерах для игроков. Игра продолжается, и код LUA, отправленный игроками, будет наблюдать и контролировать игроков, с которыми они связаны в игре.   -  person pcaston2    schedule 09.08.2012
comment
Что касается меня, я бы попытался собрать всю логику в одном месте (язык), чтобы вам не приходилось беспокоиться о синхронизации и упорядочении данных.   -  person Matthew    schedule 09.08.2012
comment
Я выбрал LUA, потому что он часто используется для сторонних надстроек. Я мог бы позволить людям использовать C#, но это было бы сложнее использовать в песочнице. Независимо от реализации, я, вероятно, приду к той же проблеме.   -  person pcaston2    schedule 09.08.2012


Ответы (3)


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

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

Я бы посоветовал вам изменить API игры.

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

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

person Orion Edwards    schedule 08.08.2012
comment
+1 за синхронизированные кадры в бесконечных циклах. Flash Player делает это с хорошим эффектом. - person spender; 09.08.2012
comment
@spender, если на то пошло, Windows тоже. - person Jonathan Henson; 09.08.2012
comment
Мне в какой-то степени нравится этот подход, однако, если я постоянно прерываю поток и перезагружаю его, среда LUA разрушается, поэтому у пользователей есть ограниченная возможность поддерживать состояние. Я полагаю, что я добавлю функцию, которую может вызывать сценарий LUA, которая переводит поток .NET в спящий режим. Я могу отслеживать, сколько времени прошло с момента последнего вызова, и если пользователь работает «горячо», я могу закрыть поток, заснуть на долгое время, а затем перезагрузить поток. Я полагаю, это заставляет пользователей быть разумными в отношении обработки. Я попробую. - person pcaston2; 09.08.2012
comment
Я добавил, что когда пользователь вызывает метод, который дает обратную связь (которая должна быть хотя бы один раз за цикл), происходит небольшой сон. На данный момент это значительно улучшило производительность, но не помогает в бесконечных циклах без вызова этой функции. - person pcaston2; 09.08.2012
comment
Я достаточно исправил проблему, используя некоторые идеи, которые были высказаны здесь. Когда пользователи вызывают функцию контроллера или функцию сна (в случае, когда они могут выполнять длительный процесс, но не решили, какое действие выполнить), таймер сбрасывается. Основной игровой движок проверяет этот таймер при каждом прогоне, и если таймер превышает определенное значение, поток уничтожается, а затем перезагружается после долгого сна. Даже если плеер постоянно зависает, похоже, процессор не сильно нагружается. Теперь большая часть ЦП используется игровым потоком, но все еще меньше 30%. Большое спасибо! - person pcaston2; 09.08.2012

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

person Jonathan Henson    schedule 08.08.2012
comment
Не уверен, насколько это было бы полезно, если код LUA блокирует поток. Я предполагаю, что это означает, что код LUA выполняется, и вы не можете вызвать Thread.Sleep(). - person Peter Ritchie; 09.08.2012
comment
@Peter, я продолжал. Сценарий LUA должен содержать часть бесконечного цикла. Код, содержащий бесконечный цикл, должен вызывать функцию сна. - person Jonathan Henson; 09.08.2012
comment
КСТАТИ. Thread.Sleep имеет степень детализации, определяемую системным квантом. Sleep(5) в основном никогда не произойдет. Скорее всего, это будет эквивалент Sleep(20) в зависимости от системы. Если у вас есть связанный с ЦП поток, который зацикливается, вы можете передать ЦП другим потокам с помощью Thread.Sleep(1). Если у вас нет цикла или определенных точек, которые вы можете вызвать Thread.Sleep, эта концепция Sleep не будет работать. - person Peter Ritchie; 09.08.2012
comment
Я не могу вызвать сон из потока, код LUA блокирует, да. Я могу получить доступ к потокам от менеджера движка, который выполняет расчеты игры вместе с игроками, может ли этот поток задушить другие? Или я могу только спать нить изнутри? - person pcaston2; 09.08.2012
comment
@Jonathan LUA — это другой язык программирования. У него нет возможности вызывать .NET Thread.Sleep(). Я не знаю, есть ли у него вообще способность спать нить. Если это не так, эта концепция не будет работать. - person Peter Ritchie; 09.08.2012
comment
@JonathanHenson Я не писал код в сценарии LUA, это может быть что угодно, он изолирован, но отправлен пользователем. Я не могу надежно контролировать, дросселируют ли они собственный поток. - person pcaston2; 09.08.2012
comment
@PeterRitchie Я знаю, однако, что в операционной системе есть вызов сна. Я думаю, что любой полезный язык программирования сможет вызвать его. - person Jonathan Henson; 09.08.2012
comment
@pcaston2 поймал, вы пробовали давать темам самый низкий приоритет при их создании? - person Jonathan Henson; 09.08.2012
comment
@JonathanHenson Да, у потоков самый низкий приоритет. Компьютер работает хорошо, но по-прежнему бездействует на 100% (4-5 потоков поглощают весь ЦП, который могут). И LUA мог бы вызвать функцию сна в .Net, если бы я тоже ее запрограммировал, но будут ли это делать пользователи или нет, будет зависеть от них. - person pcaston2; 09.08.2012
comment
@ pcaston2, им не нужно использовать функцию .NET, только операционную систему. звонок сна. Кроме того, поддерживает ли LUA какой-либо тип наследования, когда компилятор или интерпретатор может обеспечить ограничение написания хорошего кода с бесконечным циклом? - person Jonathan Henson; 09.08.2012
comment
В худшем случае у вас может быть внешний (C#) код. Время от времени приостанавливайте поток на несколько временных интервалов. - person Henk Holterman; 09.08.2012
comment
Хотя код возобновления и приостановки устарел, я, конечно, не использую никаких ресурсов в своем коде, поэтому я полагаю, что на данный момент это будет безопасный вариант. - person pcaston2; 09.08.2012
comment
@ pcaston2, я думаю, что ответ Ориона - лучший подход. Это соответствует моему комментарию к вашему вопросу. Вам нужен способ для компилятора обеспечить соблюдение хорошей практики кодирования. Если вы измените свой API так, чтобы он был просто обратным вызовом или функцией опроса, которую вы вызываете в своем собственном цикле, это лучший вариант. - person Jonathan Henson; 09.08.2012

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

Тем не менее, волокна являются родной функцией WIN32 API... самое близкое, что вы можете сделать в С#, это использовать итераторы... где вы выполняете часть работы между каждым выходом.... но вы сами решаете, когда вы хотите следующий немного работы, которую нужно выполнить, вызвав итератор.

См. 2-ю ссылку... это может быть способ использовать неуправляемый собственный API-интерфейс Fiber для переноса некоторых сопрограмм .NET, или если код LUA, который вы используете в этом потоке, является собственным, и у вас нет доступа к исходному коду. .then вы можете использовать ConvertThreadToFibre, чтобы получить контроль над ним (и решить, когда он будет запланирован, используя некоторое взаимодействие с вызовами API Fiber).

Или у вас может быть поток планирования, который использует события, чтобы сигнализировать потокам игроков, когда они могут продолжать и выполнять некоторую работу (если часть вашего кода является родной/С++, а часть - С#, тогда каждый из них может ссылаться на одни и те же дескрипторы событий... .просто используйте WIN32API или .NET API в каждом фрагменте кода).

person Colin Smith    schedule 08.08.2012
comment
Но, к сожалению, в C#/.NET нет волокон. - person Henk Holterman; 09.08.2012