Как управлять одновременным доступом к состоянию и вызовами HTTP-клиентов с помощью Clojure

Я делаю игру для программирования, чтобы изучить Clojure. По сути, это сервер, который опрашивает клиентов на наличие действий с помощью JSON через HTTP.

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

Я читал кое-что об атомах, агентах и ​​многом другом, но еще не совсем в этом разобрался.

Мой вопрос: как мне изменить структуру данных или механизм их хранения и как мне сделать опрос и другие обновления, чтобы они не мешали друг другу или работали чисто одновременно?

Я понял, что опрос, вероятно, должен быть сделан с помощью агентов (я прав?). И, возможно, мне следует добавить наблюдателя, который обновляет возвращаемое значение до состояния игрока, которым управляет сервер.

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

(def game-state {"player1" {:stuff {...} :action a1}
                 "player2" {:stuff {...} :action a3}})

Должно ли игровое состояние состоять из состояний игрока в виде атомов, например: {"player1" atom "player2" atom}

... или что-то другое?

Вдобавок ко всему этому есть HTML/JavaScript(AngularJS) страница визуализатора, которая регулярно опрашивает состояние игры с сервера.

В настоящее время, поскольку у меня нет потокового опроса, все остальное застревает, пока медленный клиент обдумывает свое следующее действие (тестовый пример).

Приветствуются любые мнения и советы о том, как правильно это сделать в Clojure.

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


person Ari P    schedule 13.05.2014    source источник
comment
На самом деле я бы использовал core.async для чего-то подобного и простые ванильные атомы для управления состоянием. И используйте как можно меньше атомов; в этом случае вам нужен только один: def game-state (atom {:player1 ... :player2 ...})   -  person Charles Duffy    schedule 13.05.2014
comment
Агенты, вообще говоря, являются правильным инструментом только тогда, когда вы хотите, чтобы они инкапсулировали состояние, управляемое потоком — если все, что вам нужно, это поток, просто используйте поток; Сам Рич заявил, что использование потоков стандартной библиотеки Java и абстракций пула потоков является правильным и идиоматичным, когда они лучше всего подходят для задачи.   -  person Charles Duffy    schedule 13.05.2014
comment
Между прочим, я настоятельно рекомендую включить The Joy of Clojure в ваш список для чтения; он тратит много времени и сосредотачивается на идиомах и выборе правильного инструмента для данной работы.   -  person Charles Duffy    schedule 13.05.2014
comment
Спасибо за советы. На самом деле я жду, когда выйдет из печати последнее издание The Joy of Clojure...   -  person Ari P    schedule 14.05.2014


Ответы (1)


Наконец-то я созрел для этого.

В итоге я изменил состояние игры на карту. Я оставил его как атом, как было предложено.

Для опроса клиентов я определил пул потоков

(def ^ExecutorService poller-thread-pool (Executors/newCachedThreadPool))

И поскольку функции Clojure являются Runnable, я просто вызываю функцию, которая запрашивает действие у клиента, а затем обновляет состояние игры для этого конкретного игрока.

(let [player-keys-and-states (seq game-state)
      threads (map request-and-update player-keys-and-states)
      tasks (map #(.submit poller-thread-pool %) threads)]
    (dorun tasks))

Дорун требуется для запуска каждого потока/функции, поскольку карта возвращает ленивую последовательность.

Изменить

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

person Ari P    schedule 13.08.2014