Как стать автором
Обновить

Комментарии 31

что-то я не совсем понял, почему он так странно и медленно ходит?
Это связано с тем, что при каждом клике, сервер оповещает всех подключенных клиентов об изменениях. Много клиентов — много сообщений от сервера, и клиент просто не успевает обрабатывать такое количество данных.

Решить это можно, например, ограничив количество отсылаемых данных сервером: не при каждом изменении оповещать клиентов, а в фиксированные промежутки слать снапшоты мира.

Помимо этого, лаги можно маскировать на клиенте, используя, например, интерполяцию данных.
Почему нет PvP? Хотя бы базового, в догонялки там поиграть…
Потому что это усложняет код как сервера, так и клиента, а поэтому удлиняет статью.
Впрочем, можно добавить пвп элемент в следующем релизе и статье.
Я вспоминаю свои муки творчества во время написания статей на хабре и умываюсь кровавыми слезами… Можно же было просто нафигачить кусков кода с комментариями на русском языке и не париться совершенно… Вот я дурак!
Данный формат выбран потому, что проще всего понять как решать задачу на примере. Поэтому основная суть статьи содержится к комментариях к коду, потому что я считаю неудобным читать отдельно код, и отдельно пояснения к нему. Плюс в статье код расположен в такой последовательности, которая позволяет проще понять устройство сервера.
Хотелось бы тут ответить, что люди приходящие в Go — это очень круто, но формат в виде листа кода действительно не подходящий вариант, если эта статья обучающая.
Мне гораздо проще разобраться в алгоритме на примере его реализации, дополненному словесным описанием.
При этом я не люблю воду. Мне все равно какая стояла погода в момент когда автор писал текст, и какого цвета в тот вечер был закат.

Какой формат был бы более приемлемым для широкой аудитории?
Главную особенность Go — упрощенное параллельное программирование вы исключили, думается, что причиной этому «не опытность».
Таким образом сервер на node.js отрабатывал бы с минимальным пингом куда больше соединений, чем ваша программа на Go.
Пакет http сам по себе асинхронен.
Главный цикл — в горутине.
Отсылка ответа в отдельной горутине, что отмечено в тексте.
Поясните, что имеется ввиду под исключением упрощенного параллельного программирования.
Все же «Многопоточность», это Node.js использует «Асинхронную модель».

— Вы не используете каналы, которые очень тесно связаны с потоками в Go и предоставляют основную производительность.
— Вы не используете так нужную переменную GOMAXPROCS для библиотеки WebSocket.

И когда у вас будет обрабатываться огромное количество данных, которые особо не нуждаются в мгновенной обработки, то потом вам придется увеличивать net.core.netdev_max_backlog, но это уже относится больше к тюнингу на будущее.
Для чего в данном случае могут понадобиться каналы?
GOMAXPROCS можно задать через переменную окружения.
serve создает по горутине на каждое входящее соединение, таким образом отвечая на каждое входящее соединение, по сути, асинхронно.
Каналы по своему определению связывают потерявшиеся рутины в просторах процессора, но в тоже время вы создаете некий «notifyClients()», чтобы оповестить других о том, что персонаж подключился к их семье. Каналами начинают думать, когда создается изначальная архитектура сервера, но для этого нужен некий багаж знаний — не постыжусь, но чтобы мыслить этим делом, мне понадобилось около 2 месяцев.

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

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

Проект синтетический, пишется для обучения, поэтому не вижу особой необходимости в этом.
Разработчики позиционируют горутины как очень легкие и дешевые треды (которые не обязательноо являются настоящими тредами). И для го-программы нормально иметь тысячи горутин.

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

Если говорить на словах о том, как бы работала система на каналах, то следующим образом:

Игрок подключается к серверу, для каждого игрока выделяется рутина с каналом, когда соединение создается или разрывается — канал уже заполнен этими данными, а они просто мониторятся в рутине каждого игрока, одновременно при изменении посылая нужный пакет.


Это избавляет вашу систему от бесконечного перебора в доп. рутинах, да еще и с постоянным выделением новой структуры в памяти.
По описанию не понял как это должно работать, и в чем преимущество перед обычной схемой.
Чистой воды пример, нет ничего рабочего:

Main loop:
func main() {
	ch := make(chan string)

	for {
		go func(ch)
	}
}

Player open connect:
func func(ch chan string) {
	text := "Hello, i am Kitty connected"
	ch <- text
}

Player loop:
func func(ch chan string) {
	for {
		if ch != nil {
			packet.Write(<- ch)
		}
	}
}
Получается что все клиенты получают один канал, из которого читают сообщения. Но разве после того, как первый клиент прочитает данные из канала, они оттуда не пропадут?
Отправлять пакет и возвращать данные в канал.
Довольно интересно. Жду продолжение.
Cannot connect to server
Выклюл сервер, потому что, как это не печально, посетители использует возможность задания произвольного имени для разжигания межнациональной вражды и рекламы.
Добавьте динамическую генерацию имён
Добавил.
Все равно cannot. Или вы его не включали?

мне влом качать исходники и ставить это все на локальном компе. Дайте посмотреть что там получилось то!:)
Сейчас должно работать.
добавьте пвп, чтобы их можно было выпиливать
Вы, достаточно вольно, используете characters в двух разных горутинах NanoHandler() и mainLoop(), даже модифицируя в обеих, не только читая. Без atomic, mutex, channel. Считаете это безопасно, консистентно? Мапы в Go безопасны только для конкурентного чения из коробки. Может быть я невнимательно прочитал ваш код.
Вы не ошиблись, это может породить веселую гонку ;)
Да, вы правы — неконсистентно и небезопасно.
Сделано это более менее сознательно, т.к. на небольшом объеме трафика не вызывало никаких проблем.
Вообще говоря, всю архитектуру стоит пересмотреть в сторону использования снимков состояния мира или изменений между ними, отсылаемых в фиксированные промежутки времени при необходимости.

Снял плашку туториала — она тут явно лишняя, я бы даже сказал вредная.
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории