Подтвердить что ты не робот

Неизменяемые функциональные объекты в сильно изменяемом домене

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

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

Но я видел блог, в котором у кого-то была небольшая игра в качестве примера, демонстрирующего неизменность. Если объект существа получил урон, он не изменил свое состояние - он вернул новый объект существа с новыми hitpoints и новый флаг "aggro to X". Однако, если мы планируем создать что-то вроде MMORPG, скажем, World of Warcraft. Сто игроков на поле битвы... возможно, тысячи атак и эффекты заклинания полировки/дебаффа, влияющие на них по-разному. Можно ли все-таки создать систему с полностью неизменяемыми объектами? Мне казалось, что каждый "тик" будет иметь гигантский рой новых инстанций. И чтобы получить текущий действительный экземпляр объектов, всем клиентам постоянно приходилось проходить какой-то центральный объект "gameworld", или?

Имеет ли шкала функционального программирования это, или это случай "лучшего инструмента для лучшей работы, возможно, не неизменяемого здесь"?

4b9b3361

Ответ 1

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

В самом деле, это так. У меня есть приложение Haskell, которое читает фид данных рынка (около пяти миллионов сообщений в течение шестичасового торгового дня, для данных, которые нам интересны) и поддерживает "текущее состояние" для различных вещей, таких как самые последние цены предложения и предложения и количества для инструментов, насколько наша модель подходит рынку и т.д. и т.д. Это довольно страшно, чтобы имитировать запуск этой программы против записанного фида в режиме профилирования и наблюдать за его распределением, а GC близок к 288 ТБ памяти (или примерно в 50 000 раз больше моего ОЗУ) в течение первых 500 секунд его запуска. (Рисунок будет значительно выше без профилирования, поскольку профилирование не только замедляет работу приложения, но также заставляет его работать и на одном ядре.)

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

Ответ 2

Обычно в функциональном программировании у вас не будут конструкторы стиля С++. Затем, хотя концептуально вы все время создаете объекты, это не значит, что компилятор должен сделать код для размещения нового объекта, потому что он не может повлиять на поведение программы. Поскольку данные неизменяемы, компилятор может видеть, какие значения вы только что указали, и то, что было передано в ваши функции.

Затем компилятор может создать действительно сжатый скомпилированный код, который просто вычисляет поля в конкретных объектах, когда они необходимы. Насколько хорошо это работает, зависит от качества используемого вами компилятора. Тем не менее, чистый функциональный программный код говорит компилятору гораздо больше о вашем коде, чем компилятор C для аналогичной программы мог бы предположить, и поэтому хороший компилятор может генерировать более эффективный код, чем вы могли бы ожидать.

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

Ответ 3

MMORPG уже является примером неизменности. Поскольку игра распределяется между серверами и системами геймеров, абсолютно нет центрального объекта "gameworld". Таким образом, любой объект, который отправляется по проводу, является неизменным. потому что он не будет изменен получателем. Вместо этого новый объект или сообщение отправляется как ответ, если он есть.

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

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

Эта игра довольно проста, поэтому я подозреваю, что множество вычисляется локально, когда это возможно. Предположим, что компьютеры двух игроков первоначально синхронизированы с точки зрения состояния игры. Затем ваш оппонент нажимает, чтобы переместить свой легкий танк в вашу базу. Сообщение (неизменяемое) отправляется вам по проводу. Поскольку алгоритм перемещения танка (возможно) детерминирован, ваша копия Command and Conquer может перемещать ваш танк противника на вашем экране, обновлять состояние игры (может быть неизменной или изменчивой). Когда легкий танк входит в зону действия вашего гигантского резервуара, ваш танк стреляет. Случайное значение генерируется на сервере (в этом случае один компьютер выбирается произвольно как сервер), чтобы определить, попадает ли выстрел вашему противнику или нет. Предполагая, что танк был поражен, и необходимо обновить до вашего танк противника, только diff — тот факт, что новый уровень брони танков уменьшился до 22%; отправляется по проводу, чтобы синхронизировать игры двух игроков. Это сообщение является неизменным.

Является ли объект на любом игровом компьютере, представляющем резервуар, изменчивым или неизменяемым, не имеет значения; он может быть реализован в любом случае. Каждый игрок напрямую не изменяет состояние игры других геймеров.

Ответ 4

Одно замечание о неизменности заключается в том, что (если оно выполнено правильно), это делает создание объекта относительно легким. Если поле является неизменным, то оно может быть разделено между экземплярами.

Ответ 5

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

Еще одна важная вещь, которую следует учитывать, - это то, что сейчас самые жесткие машины имеют 6 ядер на процессор. Рассмотрим двойную машину cpu с 6 ядрами. Один из этих 12 ядер может делать сборку мусора, и поэтому накладные расходы от разрыва множества объектов могут быть компенсированы приложением, которое легко масштабируется для этих остальных 11 ядер.

Также помните, что не каждый объект (и его суб объекты) должен быть полностью перестроен на копии. Любой ссылочный тип, который не изменился, будет принимать только одно задание ссылки, когда объект "скопирован".

Ответ 6

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

Ответ 7

Сегодня я нашел блог, который занимается ТОЧНО с вопросами, поднятыми мной в этом сообщении:

http://prog21.dadgum.com/23.html

Ответ 8

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

У Эрика Липперта есть интересные сообщения по теме неизменяемости, и они довольно интересны.