Комментарии 27
В 2020 же есть уже net core, который инструментарием и документацией не обижен, по сравнению с mono.
Третья проблема с локами понравилась — думаю почти каждый сталкивался с ними, когда писал многопоточность =)
Третья проблема с локами понравилась — думаю почти каждый сталкивался с ними, когда писал многопоточность =)
+6
Чтобы сохранить большую часть старого кода, разумно было мигрировать только на .Net 5.0. А он вышел уж слишком поздно. Я на тестовом сервере перенешел на него, порадовался появлению давно забытых на Mono номеров строк в Exceptions релизной версии. Да и все на этом.
Но это было уже весной, и он отнес ёлку обратно
+2
У меня возникло два вопроса?
1. Почему код сокетов не был переписан на асинхронные сокеты (это не те что async/await, а те что SocketAsyncEventArgs)?
2. Почему не был осуществлен переход на Core 2.x. Я в одном из проектов с Mono под ARM благополучно перешел на core под ARM, а уж 3.1 там поддерживал любые изыски.
1. Почему код сокетов не был переписан на асинхронные сокеты (это не те что async/await, а те что SocketAsyncEventArgs)?
2. Почему не был осуществлен переход на Core 2.x. Я в одном из проектов с Mono под ARM благополучно перешел на core под ARM, а уж 3.1 там поддерживал любые изыски.
0
1. Внутренность BeginSend и SendAsync существенно не отличается — оба вызывают тот же самый WSASend, разница только в том, как именно выстреливается колбек. Ну и производительность обоих методов заметно ниже, чем у IOCP.
2. Для какой цели? Core 2.x вышел в 2018м году, его производительность уступала Mono на Linux и особенно .Net 4.7 на Windows, а совместимость с старым кодом была не очень хорошей. Отрефакторить же 200000 строк кода бизнес логики ради перехода на него было бы откровенной ошибкой. Уже в 3.0 производительность была получше, но миграция все еще вызывала вопросы. Только .Net 5.0 позволил мигрировать без изменения бизнес логики, только с небольшим допиливанием ядра. Его производительность все еще чуть меньше, чем у Mono, но порядок тот же и этим уже можно пользоваться без сильной головной боли. Следующий проект будет уже на нем.
2. Для какой цели? Core 2.x вышел в 2018м году, его производительность уступала Mono на Linux и особенно .Net 4.7 на Windows, а совместимость с старым кодом была не очень хорошей. Отрефакторить же 200000 строк кода бизнес логики ради перехода на него было бы откровенной ошибкой. Уже в 3.0 производительность была получше, но миграция все еще вызывала вопросы. Только .Net 5.0 позволил мигрировать без изменения бизнес логики, только с небольшим допиливанием ядра. Его производительность все еще чуть меньше, чем у Mono, но порядок тот же и этим уже можно пользоваться без сильной головной боли. Следующий проект будет уже на нем.
0
1. Там же важнее переиспользование структур SocketAsyncEventArgs — что дает меньший расход памяти и уменьшает нагрузку на GC.
2. На уровне .NET Standard 2.0 код нормально шарился между платформами. В крайнем случае можно было настроить multitargeting на netcoreapp2.1, netstandard2.0 и net47. А на .NET Core 3 и 3.1 уже даже WPF заработал.
P.S. Вообще интересно даже что вы там такое использовали, что только .NET 5 нормально стал поддерживать?
2. На уровне .NET Standard 2.0 код нормально шарился между платформами. В крайнем случае можно было настроить multitargeting на netcoreapp2.1, netstandard2.0 и net47. А на .NET Core 3 и 3.1 уже даже WPF заработал.
P.S. Вообще интересно даже что вы там такое использовали, что только .NET 5 нормально стал поддерживать?
0
1. Если напрямую сравнивать сравнивать, то вообще BeginReceive/BeginSend в 80% случаев выполняется синхронно, тогда внутренняя структура OverlappedAsyncResult сразу попадает в Gen 0 (или Gen 1, если в отдельном потоке) и удаляется условно очень дешево, по сравнению с буферами. Но, как я писал, использование IOCP или прямой доступ к сокетам еще быстрее и удобнее. А сейчас мы вообще перешли на GameNetworkingSockets от Valve.
2. Тут накопилось столько всего, что сработал эффект домино — DynamicMethod и ILGenerator.Emit, динамическая кодогенерация через Microsoft.CSharp, объектная БД (DataTable/DataSet), Performance Counters, да и просто множество мест, где порушилась сериализация, is для структур и т.д. При том, что .Net Core 2 работал медленнее, это переделывать вообще не было смысла. Сейчас уже много чего подчищено и код компилируется c TargetFrameworks=net461;net5.0;netstandard2.0, но все-равно местами вылазят потрясающие вещи вроде разного поведения Directory.GetCurrentDirectory (не спрашивайте).
2. Тут накопилось столько всего, что сработал эффект домино — DynamicMethod и ILGenerator.Emit, динамическая кодогенерация через Microsoft.CSharp, объектная БД (DataTable/DataSet), Performance Counters, да и просто множество мест, где порушилась сериализация, is для структур и т.д. При том, что .Net Core 2 работал медленнее, это переделывать вообще не было смысла. Сейчас уже много чего подчищено и код компилируется c TargetFrameworks=net461;net5.0;netstandard2.0, но все-равно местами вылазят потрясающие вещи вроде разного поведения Directory.GetCurrentDirectory (не спрашивайте).
0
так а про что статья?
0
Там чуть ниже в тегах написано.
+1
я сужу обычно по содержанию. так вот, если отбросить весь сумбур, как я понимаю, проблема была только в том, что автор просто попытался поднять какой-то легаси код (напиленый еще для 1.1 (серьезно?)) без особого желания все это добро пересмотреть/отрефакторить, наткнулся на проблемы с дедлоками…… и все?
про это статья?
про это статья?
+3
Тут две разные истории. Легаси код начинался с версии .Net 1.1, дожил до полноценного перехода 4.0, был хорошо вычищен и отрефакторен, достиг неких высот.
Вторая история про то, как через много лет, уже далекий наследник этого кода (опять же, переписанный и вычищенный не один раз) неожиданно повторил тот же самый путь. В основном, потому что при рефакторинге вместе с водой выплеснули и ребенка — старые проблемы забылись, их методы решения тоже.
Я соглашусь, что вышло в целом сумбурно — много рассуждений, мало технических деталей, мало описаний инструментов, только основные подходы к решению проблем.
Вторая история про то, как через много лет, уже далекий наследник этого кода (опять же, переписанный и вычищенный не один раз) неожиданно повторил тот же самый путь. В основном, потому что при рефакторинге вместе с водой выплеснули и ребенка — старые проблемы забылись, их методы решения тоже.
Я соглашусь, что вышло в целом сумбурно — много рассуждений, мало технических деталей, мало описаний инструментов, только основные подходы к решению проблем.
+3
Забавное дежавю.
Чтобы один раз пройтись «по тем же граблям» — было наверное у каждого, но чтобы так последовательно — у себя не припомню.
ПС
По третьей проблеме — на счастье дедлоки чуть ли не единственная проблема многопоточности, которая имеет формально корректные решения (разумеется чем раньше эти решения появились — тем проще корректировать).
Начиная от «берём блокировки в том порядке, который никогда не приведёт к дэдлоку» и заканчивая «если дэдлок появился (в графе блокировок цикл, или как у вас по внешнему поведению) — убиваем вовлечённые в него процессы).
Чтобы один раз пройтись «по тем же граблям» — было наверное у каждого, но чтобы так последовательно — у себя не припомню.
ПС
По третьей проблеме — на счастье дедлоки чуть ли не единственная проблема многопоточности, которая имеет формально корректные решения (разумеется чем раньше эти решения появились — тем проще корректировать).
Начиная от «берём блокировки в том порядке, который никогда не приведёт к дэдлоку» и заканчивая «если дэдлок появился (в графе блокировок цикл, или как у вас по внешнему поведению) — убиваем вовлечённые в него процессы).
+1
Супер интересно, спасибо за статью. Даже не предполагал, что на дотнете в такие проблемы зарулить можно.
+1
Чем дальше читал статью, тем сильнее поступала перед глазами строчка "мыши плакали, кололись, но продолжали жрать кактус". Не в обиду, это во мне низкоуровневый прогер, вдоволь покатавшийся по граблям синхронизации, говорит. Вот уж не думал, что в высокоуровневом коде есть такие же проблемы, да ещё уходящие корнями в библиотеки.
Автору — респект однозначно.
+2
В Camelot Unchained разрабы для тестирования производительности серверов (и клиента) активно подключает ботов, которые по сути являются полноценными клиентами — отправляют и принимают пакеты, имеют заданное поведение.
Такое тестирование позволило вывести производительность на очень хороший уровень. 2000-3000 активно воюющих «игроков» в пределах одного взгляда игрока. Без лагов и тормозов сервера/клиента. Так наверное эффективнее искать проблемные места, чем на живых игроках.
Такое тестирование позволило вывести производительность на очень хороший уровень. 2000-3000 активно воюющих «игроков» в пределах одного взгляда игрока. Без лагов и тормозов сервера/клиента. Так наверное эффективнее искать проблемные места, чем на живых игроках.
+2
Да, это очень хороший вариант. Не раз о нем думал, но так и не дошли руки его реализовать.
0
Да, это очень хороший вариант. Не раз о нем думал, но так и не дошли руки его реализовать.
Заодно потом можно бота для игры продавать, дорого. И самому с ним отчаянно, денно и нощно бороться! :)).
0
Знаете, я и так сделал весьма мощный АИ (не нейросеть, скриптовый), с ним интересно играть, потому что у него есть полная информация. Конечно, это не полная имитация игроков — он не может прокачиваться и брать квесты. Но чтобы сделать именно подключаемых по сети ботов, надо потратить вагон времени на игру с неполной информацией — без знания всей карты, положения врагов, точек куда лететь для захвата флага и т.д.
0
Вы знаете — играть против АИ, у которого есть полная информация как раз очень НЕинтересно.
Сразу убивает весь метагейм, нестандартные ходы и т.п.
Остаётся только поиск «узких дырок» в логике бота (ну или пере-«фармить \ строить \ дамажить \… (подставьте что именно у вас в игре важно)»)
Сразу убивает весь метагейм, нестандартные ходы и т.п.
Остаётся только поиск «узких дырок» в логике бота (ну или пере-«фармить \ строить \ дамажить \… (подставьте что именно у вас в игре важно)»)
0
Это, наверное, лучшая статья которую я читал на хабре. Благодарю!
+1
Интересно, а ты делал игру целеком один?
0
Помню, в те времена ты говорил, что планируешь использовать движок в целом для онлайн игр, а не для конкретного эмулятора.
Судя по истории, применить больше нигде не удалось?
Судя по истории, применить больше нигде не удалось?
0
За это время было целых три проекта, которые использовали этот движок. И все закрылись до релиза или сразу после него. До боевого тестирования по-сути дожил только последний, четвертый.
0
Ну и отлично, главное попытки =).
Помню проект, ещё когда в нём не было обработки коллизий мешей и мобы выбегали из стен, камней и других непонятных мест и убивали толпой. А в целом только положительные воспоминания из тех лет.
Спасибо за проект! =)
ПС Игра реверсилась своими силами, кстати?
Помню проект, ещё когда в нём не было обработки коллизий мешей и мобы выбегали из стен, камней и других непонятных мест и убивали толпой. А в целом только положительные воспоминания из тех лет.
Спасибо за проект! =)
ПС Игра реверсилась своими силами, кстати?
0
ПС Игра реверсилась своими силами, кстати?
На самом деле у нас было большое, хоть и не очень дружное сообщество разработчиков и многие исследования делались совместно. У меня хорошо выходило копаться в протоколе, кто-то был гуру в шифровании, один коллега мастерски расшифровывал БД клиента. Ну а когда кто-то играл на официальном сервере и выкладывал дампы, то это было праздником для всех :)
0
Следующим шагом была переделка сервиса в режим консольной программы и запуск из отдельного окна cmd — так можно было найти это окно и попытаться в нем прочитать последнее, что пытался нам сообщить сервер. Это, кстати, привело к потрясающей проблеме, когда сервер останавливался из-за клика мышью в консольное окно — включался режим выбора текста, останавливавший процесс.
Прослезился.
С одной стороны жалко, что не попал в разработку в начале нулевых (хотя мог, но судьба сложилась иначе), с другой стороны, как приятно, что работаю уже с linux, и таких проблем не знал.
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Череда проблем длиною в 16 лет