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

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

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

Да, жаль что непроверенная ошибка это не ошибка компиляции. А способ обработки мне кажется это на любителя, многим наоборот нравится после исключений.
В поняшке на стадии компиляции :)
НЛО прилетело и опубликовало эту надпись здесь
До практики еще потребуется время, поэтому пока для изучения.
Да, жаль что непроверенная ошибка это не ошибка компиляции.

https://github.com/kisielk/errcheck

Очень интересный инструмент. Вы его пробовали? Как впечатление?

Успользую уже очень давно. Работает.

Спасибо. Буду пробовать.

В java тоже есть интрумент для анализа производительности и поиска узких мест — Java Mission Control.
Он идет в составе JVM.
Причем он при его использовании производительность практически не падает (от 1 до 5%).


Включается несколькими параметрами:


-Dcom.sun.management.jmxremote.rmi.port=7091
-Dcom.sun.management.jmxremote.port=7091
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false
-XX:+UnlockCommercialFeatures 
-XX:+FlightRecorder

Дальше можно зайти на сервер по ssh с перенаправлением портов:


ssh user@host -L7091:127.0.0.1:7091

Запускаем jmc и подключаемся к 127.0.0.1:7091


Вместо goroutines можно использовать fibers http://docs.paralleluniverse.co/quasar/

Спасибо. Не знал про Java Mission Control. Обязательно попробую.
Что касается quasar, я сравнивал сами языки, а не экосистему.

Без обид, но факт что вы не знаете про инструменты анализа производительности JVM, и как видно не удосужились поискать о них информацию говорит не в пользу вашего профессионализма. Но вы все же беретесь сравнивать платформы, а ведь ваш пост будут читать и за счёт авторетета хабра будут рассматривать ваше мнение так же как авторитетное.
По мимо этого. Я вижу что написание кода на go в лоб, без профилирования не дало высоких показателей(50 человек онлайн) и только после устранения узких мест был рост до 2500. Возможно на java результат будет не хуже?
Вы говорите об эффективном параллельной обработке данных на go за счёт мощных встроенных средств. Но JVM в своём арсенале уже содержит множество библиотек и Фреймворков, таких как приведено выше и даже более распространённых и проверенных, как Akka. Акторная модель скорее всего решит ваши проблемы многопоточности, не заставляя радикально менять платформу, а такой сервер как netty или модуль akkaHttp проблемы с масштабированием кол-ва соединений.

Как раз про это я и написал.
Чтобы сделать это на java мне надо было:

1) Удосужиться поискать информацию (VisualVM? YourKit? Java Mission Control, который был добавлен, начиная с java 7 и, как тут заметили, платный).
2) Попробовать каждый из них.
Вы видели, например, VisualVM? По сравнению с инструментами, предлагаемыми go, это — прошлый век.
3) Далее, я бы обнаружил, что проблемы есть не только в моём коде, но и в серверной библиотеке.
Что взять? Jetty, Netty, а может VertX или Play?
Опять масса проб и ошибок.

Мысль не в том, что на java нельзя сделать сервер быстрее.
Мысль в том, что на go для этого потребуется намного меньше времени.
Ваши пункты намекают, что ваши знания java возможно даже хуже чем знания go.
Выглядит как «я не хочу разбираться и выбирать необходимый инструмент для Java проекта, поэтому возьму мейнстримный Go».
Я хотел сравнить трудозатраты на решение одной и той же задачи в java и в go.
В go они существенно меньше для этой задачи.
Когда в Go дело доходит до использования сторонних библиотек, то ситуация становится гораздо печальнее, чем в Java. Куча библиотек, которые делают примерно одно и то же, приходится реально вчитываться в код каждой, чтобы сделать адекватный выбор.
Да что там библиотеки… Попробуйте для начала веб-фреймфорк выбрать: awesome-go#web-frameworks
Iris же. Можно делать очень быстрые микросервисы, но можно и подобие монструозного django.
Фраза «эта прекрасная машина умеет варить суп, жарить мясо и печь пироги» в 102% случаев означает, что все вышеперечисленное эта машина делает отвратительно.
Что взять? Jetty, Netty, а может VertX или Play?

Как можно всё это свалить в одну кучу и при этом делать вид что разбираетесь в Java?


  • Jetty — эффективный контейнер сервлетов. Да у него довольно эффективный IO, но его основное назначение это именно контейнер сервлетов
  • Netty — фреймворк для эффективного сетевого IO.
  • VertX — фреймворк для написания эффективных сетевых приложений. Собственно для эффективного IO использует Netty
  • Play — полноценный веб-фреймворк, которому для работы нужен контейнер сервлетов

Да даже просто причитать описание проектов на вики хватило бы что бы выбрать нужный.

Стоит добавить, что для использования JMC и Flight Recorder на приложении в production'е необходимо иметь специальную лицензию от Oracle (Java SE Advanced/Java SE Suite), как и для остальных Commercial Features. Насколько я понял из BCLA, использоваться для разработки её вполне можно.

Я удивлён что вы посылаете человека в достаточно сложный и коммерческий (начиная с 11й бесплатный) jmc, а не в async-profiler — простой и бесплатный.

В go очень мало языковых конструкций. Например, только один цикл. Go можно выучить за два вечера.

Это скорее не простота, а минималистичность. Мне нравится минималистичность, но с ней важно не переборщить (крайний пример — брейнфак. хотя нет, крайний — boolfuck). С учетом повсеместного интернета, когда достачно помнить, что что-то сделать можно, а гугл подскажет как — переборщить очень просто.


В go отказались от динамической загрузки библиотек — результат компиляции один большой исполняемый файл

Какие у этого плюсы?


В go нет warning-ов при компиляции. Любая некорректность или «многословие» — это ошибка компиляции.

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


В go встроен автоформат кода на уровне самого языка. Есть только один каноничный вид кода на go

И не дай бог мне его неудобно читать — сам виноват.


Код на go на 20-30 процентов короче аналогичного на яве (там просто не лишних слов, например, нет точки с запятой в конце каждого предложения, нет круглых скобок в операторах условия или цикла etc)

У меня такое ощущение, что где-то в мире сидят программисты, чье единственно ограничение — скорость набора, и вместо книг по программированию они ходят на курсы по скоростной печати. Остальные разницы в 20% не почувствуют, и это с Java — невероятно многословным языком.


Короче, то ли реализация принципов сомнительная, то ли примеры.


P.S. Пожалуйста, давайте не будем начинать холивар. Меня интересует Go, и это неплохой язык (как и большинство остальных). К сожалению статьи о нем на Хабре зачастую неоднозначные и вызывают кучу срачей.

Вы все грамотно написали, не холивара ради я лишь хочу варизить одну свою мысль. При сравнении языков программирования все величины относительны. Ничего не удастся привести к единой шкале просто потому что языки различны. Производительность? В какой момент времени, сразу после старта или после прогрева виртуальной машины? В каких условиях, под какой нагрузкой — слишком много условных переменных. Читаемость, понятность, поддерживаемость? Ну это вообще настолько субъективно, насколько возможно. Если бы это было не так, то не существовало столь большого числа языков на сегодняшний день. Кому-то нравится питон, кому-то больше по нраву руби. Кто-то вообще не считает интерпретируемые или выполняющиеся в ВМ языки настоящим языками. Да, возможно, история склонила определенные языки к определенным целям, условно, си — железо, перл — обработка текста, питон — математическое прототипирование и т.д. Но все же, популярность языка обуславливается свойствами, перпендикулярными всем вышеперечисленным. Мне кажется, что для того, чтобы прижиться, язык должен следовать тем же правилам, что и любой другой программный продукт. А для любого программного продукта в первую очередь важен маркетинг. Даже если продукт бесплатный. В первую очередь, важно, кто стоит за языком. Майкрософт, Гугл, Эппл или Гвидо. Здесь играет роль и психология, наверное. Но вообще, я хотел о другом сказать. Есть единственное исключение, позволяющее сравнить языки по-честному. И это — краткость языка. Речь, конечно, не идет об обфускации. Когда я изучил питон после джавы, я был удивлен, насколько короче можно записать то же самое. Почему это важно? Дело, разумеется, не в том, что программист упирается в скорость набора, а в том, что чем меньше связующего кода и лишних абстракций, тем яснее можно увидеть сам алгоритм, тем меньше приходиться тратить внимание на вещи, прямо не связанные с задачей. Да банально уставившись в экран кода, видишь больше, иногда в разы. Взять, например, геттеры-сеттеры явы, больная мозоль для многих и камень преткновения. Факт в том, что даже будучи автогенеренными, они создают огромное количество шума, который нужно учитывать. Или все эти public static final void… зачем они нужны? Короче говоря, для себя я решил, что краткость кода — одна из первостепенных по важности вещей.
НЛО прилетело и опубликовало эту надпись здесь
единственное исключение, позволяющее сравнить языки по-честному. И это — краткость языка

Вот потому-то и я мечтаю изучить APL — очень красивый и ёмкий язык!
Я бы сказал, что важна не краткость, а низкий уровень шума и простота восприятия.
Мне нравится критерий, который сформулировал Grief — язык тем лучше, чем больше смысла я вижу на одном экране.
При том, что код писал не я и я — не гений, а среднестатистический специалист.
Так перл же тогда! На одном экране можно увидеть всю не самую простую программу! Весь её смысл! Вот только как вы её понимать-то будете после этого?
Именно для этого я уточнил, что условеный «я» — не гений. Не пойму я её.
Как не пойму, например и вот такой код на scala

object IsHCons1 {

  type Aux[L[_], FH[_[_]], FT[_[_]], H0[_], T0[_] <: HList] = IsHCons1[L, FH, FT] { type H[t] = H0[t] ; type T[t] = T0[t] }

  def apply[L[_], FH[_[_]], FT[_[_]]](implicit tc: IsHCons1[L, FH, FT]): Aux[L, FH, FT, tc.H, tc.T] = tc

  implicit def mkIsHCons1[L[_], FH[_[_]], FT[_[_]]]: IsHCons1[L, FH, FT] = macro IsHCons1Macros.mkIsHCons1Impl[L, FH, FT]

}


И имено поэтому ни Perl ни Scala по данному критерию будут оценены не очень высоко.

Чтобы читать код, не надо быть гением. Надо знать язык.

Чтобы читать такой код с большой скоростью и в промышленных объёмах, надо быть именно гением.
Большинство людей тоже сможет его прочитать, но мы затратим на это слишком много усилий.
Язык — прежде всего инструмент. В идеале, человек должен иметь дело исключительно со сложностью своей задачи, а не с дополнительной сложностью, привносимой языком.
НЛО прилетело и опубликовало эту надпись здесь
Поэтому у них есть своя ниша. Для которой они — прекрасны.
У scala есть такая проблема. Многие библиотеки, в том числе стандартная, написаны очень непросто. Это или легаси, или описания DSL, удобных для применения сторонними разработчиками. Команда EPFL над этим работает, и потихоньку улучшает ситуацию. Многие вещи переписывают с нуля. Вводят дополнительные правила компиляции не позволяющие творить жесть в коде. Радует то, что во время разработки заглядывать в подобный код приходится крайне редко. А свой код можно держать в абсолютно читаемом виде. То есть работе это не мешает.
«Можно» не означает «Нужно обязательно»
Все пользуются ножами на кухне для резки продуктов.
А ими ведь можно порезать себе пальцы… но как часто реально люди это делают?
Одна из прелестных и сильных сторон Scala, как раз в разделении прикладной разработки и библиотечной.
Для прикладной разработки все эти навороты не нужны.
Эти навороты пишут ребята «семи пядей во лбу» и они их читают в лет.
Они делают библиотеки для не таких опытных разработчиков.
И это очень хорошо, что профи используют хорошие навороченные перфораторы, а не зубило с молотком.
В Go же все вынуждены пользоваться зубилом и молотком. Да, это проще, да, это понятнее.
Но все это напоминает старый анекдот «Пилу точить некогда, пилить надо».
В этом коде, кстати, читать вообще нечего.
Это же из shapeless наверняка. И читается, при знании shapeless, без проблем.
В scala (особенно в shapeless) встречается сложный для понимания код, но это не тот случай.
По компактности, с Perl вообще мало что рядом сможет стоять, но как-то на нем пишут в основном администраторы.
Справедливости ради, с недавних пор динамическая загрузка в Go так-таки появилась. Плюс статической компоновки по умолчанию — это то, что получаются самодостаточные бинарники, которые зависят разве что от libc. На практике получается очень приятно, что можно отгрузить куда-то один файл и быть достаточно уверенным, что он не упадёт из-за неудовлетворённой зависимости.

С автоформатом — да, если кто-то предпочитает другой формат, с Go получится неудобно. С другой стороны, приятие формата суть дело привычки. Вообще, в Go много крутилок и кнопочек принесли в жертву богу быстрой командной разработки — там всё сделано ради того, чтобы только что пришедший в команду джуниор или интерн начал быть эффективным на третий день вместо того чтобы неделю лупать глазами на непривычный формат кода, ещё неделю чертыхаться на отвергаемые (отформатируй согласно гайдлайнам проекта и приходи снова!) коммиты и подобные вещи. Я не берусь спорить, правильно это или нет, но определённая логика в этом есть.
К слову сказать, писать Go код можно любым удобным для себя форматированием. Главное Git-хук на go fmt поставить.
И тогда гошное форматирование будет на уровне автозамены CRLF.

Читать да, только в каноничной форме :)
На практике получается очень приятно, что можно отгрузить куда-то один файл и быть достаточно уверенным, что он не упадёт из-за неудовлетворённой зависимости.

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


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

Я не знаю как у вас, но в моей IDE есть автоформатирование кода. Весь читаемый мной код я прогоняю через него, получая привычный мной формат. Это решает те же проблемы, но никак никого не ограничивает.

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

А кто-то запретил? В Go есть динамическая компоновка (я вроде бы упомянул ответом выше), статическая там просто по умолчанию.

По поводу форматирования — ну хорошо, чужой код вы прогоните через автоформатирование и будете читать так, как вам нравится. Но писать-то вам код придётся в соответствии с гайдлайнами того проекта, куда вас позовут. Или вы конвертируете и туда и обратно? Переформатируете всё написанное перед коммитом? Кстати, если что, с Go вам тоже никто не мешает так сделать. Просто есть официальный стандарт оформления и есть официальная утилита, которая форматирует. На вашей машине никто вас не заставляет ими пользоваться, дело хозяйское.
А кто-то запретил? В Go есть динамическая компоновка (я вроде бы упомянул ответом выше), статическая там просто по умолчанию.

Я так понял, что изначально ее не было.


Просто есть официальный стандарт оформления и есть официальная утилита, которая форматирует. На вашей машине никто вас не заставляет ими пользоваться, дело хозяйское.

То есть это не требования, а рекомендации? Но тогда все равно каждый будет форматировать как ему угодно. Возникает ощущение, что Go — язык непонятных искусственных ограничений.

Изначально не было. Ну так и язык относительно новый, во многих языках изначально много чего не было. Её не запрещали, её просто не сделали сразу. Вопрос приоритетов. Питону необходимость везде тащить рантайм и отсутствие динамических библиотек (хотя вроде уже можно что-то такое с Cython сделать? пусть знающие поправят) не мешает в топе TIOBE висеть и пользоваться народной любовью.

Да, это не требования — не ограничения — а рекомендации. Поэтому я не совсем, признаться, понимаю, откуда ощущение взялось. Тут фокус в другом — есть такая штука как сила умолчаний. Если в языке из коробки есть официально рекомендованный стиль оформления и даже утилита, то в сообществе создаётся тренд, и очень немногие от него отходят. Получается, что и волки сыты (можно форматировать как угодно, если есть желание), и овцы целы (подавляющее большинство кода всё равно в стандартном единообразном стиле). Это просто психологический приём, чтобы большинство разработчиков безболезненно и быстро миновали фазу «так, в каком стиле мне начать писать код» и начали писать собственно код.
Да, это не требования — не ограничения — а рекомендации.

Тогда странно выглядит то, что сначала очень старательно продавали статическую линковку как killer feature. Удивительное будет время, когда найдут какой-нибудь приятный баг где-нибудь в crypto. Сколько народу не пересоберёт (учитывая, что используют glide/gob далеко не везде), а сколько — забьёт?

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


По поводу багфиксов — это старый спор, и я не думаю, что там есть какая-то правда. Это больше спор о том, кому быть виноватым — майнтайнерам пакетов с библиотеками, майнтайнерам приложений, или вообще нерадивым админам, которые ничего и никогда не обновляют. Если так подумать, то с тем же успехом можно накатить обновление библиотеки с незамеченным zero day (а может и с нарочно внесённым), и моментально все динамически слинкованные приложения становятся уязвимыми. Мне кажется, там проблема вообще в другой плоскости лежит.

Тут рядом ещё ходит проблема невоспроизводимых билдов благодаря утилите go get, которая местами усиливает (более новая версия в репозитории может оказаться несовместимой и софт оставят необновлённым), местами — ослабляет (go get принесёт последнюю версию зависимости) вышеописанную проблему. Ну и всё это надо помножить на реальное разнообразие: кто-то вендорит зависимости, кто-то говорит "дёрните go get ..." при сборке; кто-то предупреждает о необходимости чистого GOPATH, кто-то предполагает, что он у вас единственный и вы будете использовать те же версии библиотек, что и в других своих проектах.


Меня лично радует, что glide пошёл в массы, но это очень субъективная штука, т. к. я на go не пишу, то, по сути, рассматриваю проблемы с точки зрения мейнтейнера, а не разработчика.

Да, это больной момент у всей экосистемы. :( Зря на потом оставили. Я думаю, что вендоринг если не решит проблему, то хотя бы однородной сделает. Кстати, спасибо за наводку на glide, я пользовался gb-vendor, но glide выглядит хорошо (я тоже ничего на Go по большому счёту не пишу, но быть в курсе стараюсь).

glide и работает хорошо, не только выглядит
без каких-либо ментальных или физических телодвижений

Я пишу на С++, телодвижения сводятся к указанию пути к библиотеке и подключению заголовка. Куда уж проще?

Я тоже пишу на C++. Добавьте телодвижения автора библиотеки, который обеспечил возможность сборки статической библиотеки, и майнтайнеров пакетов, которые собрали её под нужную архитектуру и дистрибутив и доставили вам. :) Представьте, что в репах статической библиотеки нет (или вообще нет). И автор не предусмотрел сборку статической библиотеки (или вообще чего-нибудь толкового, или всё зависит от экзотичной системы сборки с запутанными и хрупкими конфигами). Мне в целом нравится, на чём я пишу, но мне кажется, что «куда уж проще» — это не про сборку и зависимости в C++. :)

НЛО прилетело и опубликовало эту надпись здесь

Были, но они подключались по одной в процессе разработки. Больше получаса на поиск библиотеки с нужным функционалом, её сборку и подключение уходило редко.


Хотя если их несколько сотен, то и правда уйдет неделя.

НЛО прилетело и опубликовало эту надпись здесь

image


Если серьезно, то на плюсах пишут там, где нужна максимальная производительность. Несмотря на все его недостатки (а каждый находит десяток-другой своих), реальной альтернативы нет. Возможно, ей станет Rust.


З.Ы. В С++ есть std::array и std::vector, зачем пользоваться сишным массивом?

НЛО прилетело и опубликовало эту надпись здесь
или язык действительно безнадёжно затянут в бездну обратной совместимости?

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


В более новых языках типа Rust действительно многое проще (в том плане, что компилятор даст по рукам, если что), но суть остаётся той же: такие решения приходится принимать самому: если нужные виртуальные функции, то используем трейт-объекты и т.д.

НЛО прилетело и опубликовало эту надпись здесь

Там всё плохо… Есть динамическая линковка — опция компилятора -dynlink. Это, насколько я понимаю, вызов кода из сторонних so и dll. Но свою динамическую библиотеку создать на Go — нельзя. И также нельзя подгрузить в рантайме произвольную библиотеку и вызвать из неё функцию.


Другими словами, реализовать плагины в программе просто невозможно. И это главная проблема сейчас, как по мне. Это тормозит развитие http://gogs.io/, чтобы решить эту проблему ребята из http://caddyserver.com/ написали своё решение, которые перекомпилирует исходники с нужными модулями по выбору пользователя...


Вот, к примеру, один из тасков о динамической загрузке. Закрыт. Заброшен: https://github.com/golang/go/issues/13751

А -buildmode=c-shared, которая в 1.5 появилась, это не оно? Можно из Go сделать .so, потом использовать откуда угодно, в том числе из Go. Понятно, что не без ограничений по экспортам, но всё же. Вот тут подробнее: http://www.darkcoding.net/software/building-shared-libraries-in-go-part-1/

Но можно ли эти so или dll загрузить обратно в Go динамически? Вызвать функцию, а потом выгрузить из памяти?


Как я могу реализовать систему плагинов к моему приложению на Go без перекомпиляции оного?

Именно чтобы руками, как с dlopen() или LoadLibrary()? С этим пока не очень просто. В принципе, насколько я понимаю (поправьте, кто это дело ковырял), можно загрузить через cgo. Код получается, мягко говоря, некрасивый, и не уверен, как сделать на не-POSIX платформе, но в целом должно работать. Что-то вроде такого:


// #cgo LDFLAGS: -ldl
// #include <dlfcn.h>

import "C"

// ...и дальше по тексту, handle := C.dlopen(...) и прочее.

Насколько удобно будет так делать развесистую систему плагинов — не знаю, надо пробовать и смотреть. Ну и, понятно, портируемость пострадала.

Можно с помощью стандартного пакета syscall.
А я вообще не соглашусь с тем, что код на Go короче. Я пробовал, получилось более многословно, максимально приближено к C в плане последовательности действий, разве что очисткой памяти занимается сам рантайм.
>>Но очень быстро все уперлось в производительность.
>>На одном сервере можно было запустить не более 300 клиентов.

Я конечно извиняюсь, но думаю после этого можно не читать дальше. А в го у вас сколько клиентов получилось? 310?
Статью не читаю, комментарии пишу. Автор же написал что 2500
Ну т.е. после того как он стал использовать профилировщик (который никто ему не мешал использовать на джаве) он оптимизировал приложение. Это явно плюс языка go

Я думаю что го был создан для дешевой раб силы, все его ограничения связаны с низким порогом вхождения дабы не заморачивать светлые умы
Автор подробно описал причины почему он использовал профилировщик на го и не использовал на джаве. А еще комментарием выше ему явно указали как он мог бы таки его использовать.
И то что автор не использовал профилировщик не объясняет почему вы не читаете статью, но оставляете комментарии…
Потому что заявления — я написал сервер на джаве и он обрабатывал всего 300 клиентов (без тех. подробностей) это какая-то софистика.
А я вообще использовал nodejs который обрабатывал пол миллиона клиентов, так что давайте все использовать nodejs )

мне как-то скучно было и я на жавоском сервере на домашнем компе поднял 2 миллиона активных соединений, потребовалось 10гб оперативы, но старенький амд осилил ^_^

Если там просто пустые соединения, то разницы бы не было.

Если сервер имеет сложную логику и «тянет» мало клиентов, то вывести его на нужный уровень производительности в go займет существенно меньше времени, чем выполнение той же задачи в java.

(Хотя, разумется, это возможно и в java и вообще на любом языке)
Сервера бывают разные. Ваши полмиллина клиентов — это игровые клиетны в реальном времени, как у меня?

Кроме этого, вы не захотели понять суть статьи. Она не о том, что go — лучший язык.
И не о том, что в ява нет профайлеров.
Я сравнил усилия, которые от меня потребовали языки, чтобы сделать одно и то же. Go в данном случае потребовал в разы меньше.

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

Да ладно? Вы даже не пытались профайлить в джаве, о каких таких «потребовал в разы меньше» можно говорить?
Как я понял, у автора «потребовал в разы меньше усилий» процесс профилирования, собственно.
Не только он. Существенная экономия была достигнута за счёт профилирования и за счёт ловли race conditions.
Несущественная — за счет меньшего объема кода.
Комментарий на который я ответил, как бы подразумевает, что вы не можете сравнивать сколько вы времени сэкономили, потому что профилировать код на Java вы даже не пытались.

Поэтому в статье у вас и получилась экономия только на том, что вы быстрее освоили один профайлер, чем другой.
Ответил ниже. Могу. Потому что неоднократно ранее делал это с другими проектами.
Хм, вот тут я вас не очень понимаю.
Если вы уже делали профилирование на других проектах, то у вас уже должны быть достаточные навыки для работы с профилированием в Java, что бы не писать о том, какое оно сложное и не понятное.

То вы указываете, что работаете с Java целых 18 лет, но почему-то у вас свеженаписанный сервер не держал больше 300 коннектов, что явно указывает на то, что для его написания не использовались нужные технологии.

Так же, непонятки с профилированием, хотя за 18 лет, у вас точно должен был быть опыт профилирования хотя бы одного многопоточного приложения на java, а тулзов для race detector там полно.

Так же. вы тут где-то признавались с том, что не работали/не знаете ни одну библиотеку, для работы с серверами на Java, что еще более странно, с 18-летним опытом, если даже я, который впринципе не работает с Java в production, поработал с Netty.

Как-то немного многовато нестыковок.
Достаточные навыки в чем-то не противоречат отношению к этом чему-то, как к сложному и неудобному.

Про сервер вы правы. Ранее я писал на java что угодно (начиная от web (бизнес системы) и кончая играми, Eclipse RCP или CORBA-SNMP gateway), кроме серверов реального времени, использующих Websocket. Этот сервер (а точнее — прототип) я написал очень быстро и без оглядки на performance. На этом этапе я определял что вообще должен делать этот сервер, по сути — проектировал игру. С технологией (библиотекой) я, кстати, действительно, ошибся.
Performance-ом собирался заняться на следующем этапе. Уже «предвкушал» приятную возню с VisualVM. Но наткнулся на описание профайлера в языке go (на который уже давненько с интересом посматривал). Описание понравилось. Решил сделать production вариант на go. Сделал. Опытом более чем удовлетворен.
Вы путаете две вещи «я не пытался профайлить именно этот проект» (да, не пытался. Примерно знал во что оно выльется) и «я не пытался профайлить в java вообще» (такой опыт был, иначе не о чем было бы говорить)
Го задалбывает приведением типов. И функции которые конвертнут из одного типа в другой всегда болтаются в разных библиотеках. Я был бы счастлив если был бы какой-то единый способ приведения стандартных типов. Есть странные вещи, например в условиях нельзя сравнивать целые и дробные, это очень бесит в циклах.
Вот это проблемы у людей!

Нет бесплатного профайлера в Java? Конечно есть, хорош для решения основных пробем с производительностью, имеется куча плагинов, называется VisualVM.

Нельзя подключиться профайлером к удаленному серверу? Конечно можно, включаем JMX, пробрасываем порт и вперед. На самом сервере всегда можно заюзать консольные утилитки типа jmap, hprof и т.п.

Race conditions — это действительно головная боль писателей многопоточных приложений, но далеко не всех. Некоторые все-таки знают про shared mutable state и избегают его, используя либо стратегию share-nothing (каналы в Go, Akka — в Java), либо функциональное программирование (переход на immutable).

Стоит ли ява программисту полностью переходить на go? Нет.


А вот с выводом-то особо и не поспоришь :)
Ваша мысль выглядит примерно так «Нельзя удалять гланды автогеном? Конечно, можно! Просто надо делать это через задний проход!»
Я нигде не сказал, что в яве нет профайлера.
Я сравнивал производительность инструментов (java + какой-то профайлер) vs (go + встроенный профайлер)
Go в несколько раз выиграл в моём случае. Работать было быстро, удобно и приятно.
Глаз сильно зацепился за это
Но важно понимать, что этот самый коллектор будет запускаться каждые несколько секунд и заметно притормаживать систему.

Это ж насколько сильно нужно гадить в хип, чтобы заметить работу GC? Это точно не про Java?
НЛО прилетело и опубликовало эту надпись здесь
Ну так мы и не про Go1.2 какой-нибудь сейчас говорим, верно? На 1.4 еще помню какие-то задержки на сотни мс, сейчас же на 1.6 даже 10-12 мс — это уже зачем-то много гадили в хип. Типичное время работы GC <= 1мс на наших проектах.
Нужно завести игровой сервер. Поднять там 2500 клиентов, каждый из которых будет отправлять в среднем 50 сообщений в секунду и получать примерно 750 (через web socket).
Работа gc замечается в едва заметных глазу лагах при передвижении игровых объектов.
Так это не gc скорей всего виноват, а вы с объектами, вероятно, неправильно работаете. Часто инстанциируете, нету пулов и т.п. У нас сервера игровые на java/C#, никаких лагов не наблюдаем связанных с gc.
Что касается объектов, то нет. Мы как раз оптимизировали здесь всё, что только можно было. В куче почти ничего не создаётся. Пулы есть.

Возможные причины такой разницы:

1) GC в go пока хуже, чем в java. До версии 1.5 был вообще ужасен. Но всё еще заметно хуже.
2) Разная нагрузка на сервер. Наш получает от каждого из 2500 клиентов примерно 50 сообщений в секунду. Обратно отсылает примерно 750. Плюс имеет очень много межпоточных коммуникаций.
3) Разные требования к серверу, обусловленные устройством самой игры. Если у нас влючить gc, появлется едва заметное дрожание кораблика раз в несколько секунд. Оно трудноуловимо, но создает ощущение, что с игрой что-то не так.
GC может и похуже, но:
  • escape analysis позволяет много чего оставить на стеке и уменьшить мусор в хипе;
  • многие типы нативны и хранятся как есть без лишних косвенных обращений, уменьшая нагрузку на GC при сборке

И получается хорошо на больших хипах (десятки ГБ).

P.S. У нас на пушилках, рассылающих около миллиарда пушей в сутки каждая (с огромной кучей логики, горутин, каналов, и т.п.), сейчас сборка gc занимает 12мс время от времени (и там даже sync.Pool почти нет).
На более оптимизированных (пулы и профилировка наше все) демонах сборка редко когда даже 1мс занимает.
Update: После перевода проекта на go1.7 проблемы с gc исчезли полностью.
Теперь его не отключаем, ибо он и так незаметен.
Ого, уже на 1.7. Я пока опасаюсь переводить прод на него)
У нас еще не было релиза. Поэтому такие смелые.
Но плюсы ощутимы. Кроме решения проблемы gc оно еще и процессора есть примерно на 35-30% меньше, чем 1.6
Сам файл вместо 6.5мб весит 4.5 (хотя последнее и не важно для нас)
Смешно наблюдать за этими потугами недоразработчиков.
Я из .NET, но тут я с Java.
Сколько же вас развелось таких, кто не написав ничего серьезного и не имея за плечами нормального опыта, прыгают с языка на язык и успевают между этим писать поучительные статьи? Другие успевают преподавать с таким «богатым» опытом.
Да, чувак, то что ты не умеешь пользоваться инструментами — это Java виновата, совершенно точно. проблема точно в ней!
Поясните каким образом вы оценивали мой опыт и почему решили, что я прыгаю с языка на язык?

Что касается инструментов, то лучшие инструменты остаются лучшими, несмотря на то, что я или вы умеете работать и с плохими.
Чем больше общаешься в англоязычных коммьюнити, тем страшнее читать вот такие комментарии, которые ещё и кто-то плюсует.

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

А вот почему вы считаете, что вы имеете права оскорблять других людей за их труды, мне не ясно. К сожалению, о русскоязычных коммьюнити мнение складывается по вот таким вот зазнавшимся «специалистам, написавшим много серьезного», как вы.
Большое спасибо за ваши добрые слова.
Я все еще не понимаю, почему вам не нравятся такие комментарии.
Они абсолютно справделивы.
Go-коммюнити в Рунете уже достало писать такие статьи, где они сравнивают какой-то язык с Go, допуская в сравнении серьезные ошибки.

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

Касательно статьи — пусть даже автор 1000 раз не прав, ему можно указать на ошибки уважительно и без оскорблений. Это будет правильней по всему пунктам. Почему-то в рунете это не сильно практикуется, увы.

Опыт работы с профайлером в Go, кстати, и вправду, великолепен. Это не про «нагуглить» это про реальную продуктивность и затраченное время и когнитивные усилия от возникновения проблемы до ее фактического решения с помощью профайлера.

Поговорив с автором я вытянул из него, что у него довольно богатый опыт с VisualVM и он от него устал. Это существенно дополнило мое впечатление о статье.


Касательно статьи — пусть даже автор 1000 раз не прав, ему можно указать на ошибки уважительно и без оскорблений. Это будет правильней по всему пунктам. Почему-то в рунете это не сильно практикуется, увы.

Можно сказать спасибо "интересным" статьям про Go ранее. Например, ту, в которой у компании крутились микросервисы на Java в Tomcat.

Если я в тексте вижу фразы — «я тут написал, а оно не работает, наверное такое на Java вообще не возможно написать», и еще приплести сюда какой-то недоразвитый язык и поставить его выше прекрасно зарекомендовавшего себя инструмента, который используют десятки лет, то готов многое высказать такому специалисту.
И ведь, какой-нибудь школьник почитав этот «труд» реально подумает, что лучше Go ничего нет, а это уже просто диверсия какая-то.
Иногда складывается впечатление, что это какие-то новые маркетинговые войны и реклама идет самыми грязными методами и просто внаглую
НЛО прилетело и опубликовало эту надпись здесь
Это справедливо, если вы ограничены одной технологией в принципе. Но чем больше вы набираетесь опыта, тем больше понимаете, что выбор технологии (языка/базы данных/алгоритма/фреймворка/etc) это тоже часть работы инженера, и едва ли не важнейшая.

Ограничивая свои знания одной технологией, вы повышаете свой knowledge debt, который будете выплачивать тем, что будете менее продуктивны. Вы могли бы точно так же зафанатеть по фортрану и считать, что те, кто предлагают вам другие языки «просто недостаточно хорошо разобрались» в фортране. Нет, нет и нет. Это ваша ответственность максимально объективно владеть ситуацией, знать плюсы и минусы технологий, уметь использовать как-минимум основные из них и уметь выбирать нужный инструмент для нужной задачи.

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

Ну, если, конечно, нет цели устроиться чернорабочим в гугл.
Безусловно это только в вашем джава-мире, из которого автор, в отличие от многих комментаторов сумел выглянуть. А субъективные рассуждения про «сложнее значит лучше», с которыми я в корне не согласен, и «чернорабочие в гугл» — это вообще никакой критики не выдерживает.
> субъективные рассуждения про «сложнее значит лучше», с которыми я в корне не согласен

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

Просто я умею просматривать за ужином бенчмарки, а не доверять без разбору непонятно откуда взявшимся текстам.
НЛО прилетело и опубликовало эту надпись здесь

В это веришь до первого пойманного бага в компиляторе :)

НЛО прилетело и опубликовало эту надпись здесь

Я вот об этом:


если у вас что-то не получается, или что-то не работает, не ищите проблему во фрэймвоке или библиотеках, ищите проблему в вашем коде

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

НЛО прилетело и опубликовало эту надпись здесь
приплести сюда какой-то недоразвитый язык

Вы же понимаете, что с такой риторикой с вами общаться, как со взрослым человеком, нет смысла, правда?

Если бы мне пришлось выбирать из двух кандидатов в свою команду, я бы однозначно выбрал автора статьи, а вас бы сразу в черный список занёс. Автор умеет осваивать новые вещи, умеет учиться, умеет делиться знаниями и не боится почувствовать себя новичком. Это очень ценно. Вы же фанатичны в одной технологии, не умеете адекватно общаться, обвешались в стереотипах и не умеете объективно смотреть на выбор технологии, как на один из важных элементов работы разработчика. По-моему, выбор очевиден.
Вы вроде взрослый человек, а ведетесь на какие-то, очень странные вещи.
Вы видимо, тоже проскочили уровень, где начинаешь смотреть на ващи более трезво.
С чего вы взяли, что человек выше будет учится и делать что--то лучше? Он язык приплетает для технологии, в некоторых случаях, это бывает оправданно. Такие люди будут вас доить, каждый год переписывая свое творчество на очередной язык.
Go хорош для сетевой мелочи и не больше.
Уж называть меня консерватором в технологиях просто смешно.
Просто вы своими (Go) статьями, честно, уже достали.
Просто вы своими (Go) статьями, честно, уже достали.

Вы всегда можете пойти в угол и поплакать, если кто-то пишет статьи про ненавистную вам технологии. Очень взрослый уровень хабра и русскоязычного джава-сообщества в целом.
А вы смеееешноой…
Т.е. увязывание тезисов являющихся явно холиворными в статье — вы называете взрослым поведением? Вы или пропустили их (соглашаясь с авторским фанатским мнением по этим пунктам) или явно троллите. Да и в комментариях автор так и не смог внятно назвать/показать плюсы перехода. И после этого вы его называете новатором? Простите — но в шею гнать таких новаторов!

Для большей ясности процитирую набросы на вентилятор:
«Код на go на 20-30 процентов короче аналогичного на яве (там просто не лишних слов, например, нет точки с запятой в конце каждого предложения, нет круглых скобок в операторах условия или цикла etc)»
Что значит на 20-30% короче? С какой версией сравнивалось? Напомню — лямбды, диамонды позволяют сильно экономить на обязательной выразительности кода. Приведённые же примеры — просто шик! Точка с запятой на конце! Как сложно поставить! Отсутствие скобок на ифе/цикле — опять же вкусовщина. Мне вот скобки нравятся — они визуально помогают выделить блок условия.

«В go очень быстрый компилятор (несколько секунд на компиляцию большого проекта)»
Вообще непонятная фраза. Компилятор в Java тоже очень быстрый. + различные механизмы онлайн подгрузки классов. Нет, если бы была статься "… глазами программиста C++" я бы мог понять… Но Java-то тут причём?

«1) Используя метод пристального взгляда искать в коде неэффективные места, пробовать их исправлять и, после каждого изменения, вновь запускать нагрузочные тесты. Этот способ очевидно неэффективен.»
На !1ом! месте человек рассматривает метод визуального профилиривония… СЕРЬЁЗНО???

«2) Погрузиться в изучение альтернативных серверных библиотек, пробовать разные варианты. Это тоже не дает никаких гарантий — возможно проблемы в моём собственном коде, или вообще в самом языке java.»
Это надо было делать ДО начала написания кода. Потому что с неплохой вероятностью существенный кусок кода будет просто выброшен. И раз уж существующих знаний нужных библиотек нет — это надо было делать ОБЯЗАТЕЛЬНО.

«3) Наконец, я мог купить один или несколько платных профилировщиков и попробовать получить какую-то информацию от них. Но и тут есть проблемы. Если использовать локальный сервер, стоящий у нас в офисе, я не мог создать нужной нагрузки, поскольку у нас в офисе нет нужного количества свободных машин, чтобы запустить несколько тысяч клиентов. Если же использовать внешний сервер, то требовалась довольно сложная конфигурация, чтобы запустить там профилировщик. Наконец, выбор профилировщика сам по себе является нетривиальной задачей.»
Тут сразу несколько шедевров: зачем-то понадобилось покупать профилировщики и пробовать получить информацию от них. Во-первых профилировщиков очень много. И платных и бесплатных. Если человек (программист Java) давно работает в индустрии — ему не надо покупать, необходимый набор у него есть. При этом автор не пожаловался на то, что профилировщики влёгкую могут врать (привет JUG движуха в Питере, которая знает!). Но почему-то пожаловался (кстати, в исходной статье он называл вообще невозможным) на трудности запуска профилировщика на внешнем сервисе. Что ему мешало поднять на своём сервере виртуалку — опять же тайна. Да и просто «сложно создать достаточную нагрузку»… это как? Сервер слишком жирный? Ну так не пускайте за пределы 2х-4х ядер JVM! Да и даже в этом случае — вполне можно было сделать кластер-бота, который легко нужную нагрузку даст. При этом решение с нагрузкой так и не было озвучено. Взяли Go и сразу всё само образовалось?

ну и самое вкусное:
«Go создавался гораздо позже и на сегодня в нем присутствует все, что востребовано сейчас и ничего лишнего.»
Это после жалоб-то на отсутствие механизма исключений («Ужасная — обработка ошибок путем проверки возвращаемого функцией кода.»)?! После жалоб на отсутствие генериков («Плохая — это отсутствие generic-ов.»)?!

Не исповедимы, видимо, не только «пути господни», но и мысли человечьи…

PS корм закончился, больших жирных и зелёных просьба отойти. Готов только к нормальному диалогу.
Не смешной совсем. Это реально не смешно.
divan0 Какой-то ярый, непримиримый фанат Go.
Он приплетает все, что угодно в качестве аргументов против тех, кто сомневается в Go.
При чем технических аргументов очень мало. В основном он скатывается на личности и их качества.
При чем эта черта отмечается многими в разных Go тусовках. Такое ощущение, что в Go так принято.
Любой камент против Go вызывает бурную, просто неадекватную реакцию.
Я, наверное, что-то не понимаю, но я написал выше конкретно про то, что оскорблять людей — это неправильно, и строить дискуссию со слов «недоразвитый язык» не имеет смысла. Если вы в этом видите «любой камент», «неадекватную реакцию» и «скатывается на личности», то мы говорим на разных языках.

Если честно, то я очень рад, что почти не общаюсь в русскоязычном сегменте — очень отвык уже от такого уровня общения. Но автор статьи не заслуживает того, чтобы его оскорбляли. Человек поделился опытом, потратил время, написал пост на техническом ресурсе, и вынужден терпеть оскорбления. Со стороны выглядит дико и мне жаль, что здесь это норма. Мы люди, пишем софт для людей, мы можем находить общий язык, если соблюдать простые базовые правила общения. Во всем мире это работает, кроме рунета.
Где-то высказывали мнение, что это во многом из-за того, что Go был создан в Google Робом Пайком. И тут сложились два фактора: все, что делает «корпорация добра» по-умолчанию идеально, и всё, что делает такой человек, как Пайк — тоже идеально и все архитектурные решения, сколь бы нетрадиционными они ни были, по-умолчанию не могут быть подвержены критике из-за личности автора (если почитаете другие комментарии этого товарища, то там часто встречается что-то вроде «вы еще Пайка поучите», «Пайк знает, как правильно» и так далее).

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

JMC и VisualVM умеют подключаться к приложению по tcp. YourKit умеет подключаться удаленно. Какие профайлеры вы видели (и читали документацию к ним, ессно)?

Неаккуатно написал. Имел ввиду существенно различную сложность при использовании профайлеров java и go.
Сначала для многозадачных приложений в языках программирования были придуманы процессы.

А за такое автора хочется бить тапком. Процессы — это сущность уровня ОС, они существуют не в языках программирования. То, что из ЯП можно дернуть соответствующий syscall (или библиотечную функцию) для порождения процесса не означает, что они "придуманы в языках программирования".

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

Для создания треда в linux, например, обычно дергается syscall clone, если правильно помню. Создание нового процесса может выпоняться им же, просто с другими флагами, касающимися выделения нового стека, адресного пространства и т. п. Принципиального отличия с точки зрения ядра нет.


Основной недостаток использования процессов — более дорогой IPC (хотя иногда выкручиваются через /dev/shm) по сравнению с использованием общей памяти разными потоками в рамках единого адресного пространства.

Именно так. Спасибо
Автор!!! 300 клиентов на сервер!!! Вот это да!!!
На плюсах писал сервер для ММОРПГ мне в страшном сне не могло такое присниться… минимум 10 000 при использовании самых жестких процедур
.
А хотите а скажу как можно создать эмулятор ЛЮБОГО количества клиентов на ОДНОМ клиенте?
Берете вайршарк, пишете пакеты(еще лучше, свой сниффер), запускаете клиент, делаете нужные действия, пишете пакеты.
А потом те же пакеты размножаете любым доступным способом. Вплоть до забивания пропускного канала :-) Так как вы автор, вы знаете где у вас в пакете хранятся уникальные для каждого пакета id и знаете как легко их можно поменять. Так что — это реально легко и просто :-)
Почему свой сниффер лучше — понятно?

Дайте, я еще угадаю: положение игроков рассылается не каждому по запросу, а от каждого каждому? В смысле, пришел пакет на изменение положения, это изменение разослали всем в зоне?

П.с. это не в смысле «блин… какой дурак», а в плане «ооо!!! И я таким же молодым был» :-)
В смысле, пришел пакет на изменение положения, это изменение разослали всем в зоне?

А как правильно? игры ни разу не делал
У нас было так — в зоне храниться лог обработанных событий за последнюю минуту(т.е. не юзер2 жмет влево, а персонаж такой-то изменяет координаты на столько-то). Приходит пакет и говорит: «я хочу лог зоны с такой-то секунды и такой-то миллисекунды». Ему в ответ: «вот тебе родной», и сервером передается лог событий. Клиент, соответственно, запрашивает состояние зоны каждый раз, как поймал ответ, но не чаще чем через 250 мс от отправки предыдущего пакета, и не реже чем раз в четыре секунды(udp-пакеты могут теряться). Т.е. что пинг 50, что пинг 250 — без разницы.
Почему это лучше? Потому что у клиента пинг может достигать до трех-четырех секунд… и он все равно будет видеть все, что происходило.
У нас время жизни клиента без ответа было 15 секунд. Т.е. если от клиента не было ни одного пакета за 15 секунд, он вышел и должен заново проходить авторизацию. Этого хватало на самые плохие пинги(вроде, на Камчатке был клиент, но сейчас уже не уверен, где-то в дальних гребенях со стабильным пингом в три секунды).
При этом, когда идет рассылка любых изменений всем в зоне, количество пакетов растет квадратично в зависимости от количества клиентов.
Как вы представляете многопользовательский шутер с временем жизни клиента без ответа в 15 секунд?
А что вы делаете, если от пользователя перестали приходить пакеты, но корректно он не вышел?
За 15 секунд пользователь, если у него проблемы, успевает перезагрузиться и снова запустить клиент.

И да, его за это время могут даже не убить. Если он успел заныкаться или находится на стартовой позиции.
Если от него перестали приходить пакеты, его коннект убивается сервером (примерно, через секунду)
Думаю, наши игры очень разные. Моя больше всего похожа на agar.io/slither.io.
Там всё очень быстро происходит. 15 секунд — неприемлемо огромный интервал
Да, я, с моими пингами, не смог поиграть ни в одну ни в другую :-)
Позвольте спросить у вас, почему вы выбрали способ именно «пересылки/повторении» трафика на свой сервер?

Ведь наверняка при планировании архитектуры игры, вы могли бы заранее создать инструменты генерирующие эти самые запросы. Например, клиент использует некоторую библиотеку, которая отправляет/принимает запросы, потом её подготовить (можно урезать), и после вызывать нужные методы в большом количестве и с нужными параметрами.

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

Спасибо за ответ.
Во-первых, судя по статье, я подумал, что автор не очень опытный разработчик. И потому я посоветовал самый просто способ. Ну, на мой взгляд :-)
Во-вторых, исследование СВОЕГО трафика — это одна из вещей, которой нужно заниматься при оптимизации клиента, о которой мало кто помнит.
В-третьих, инструмент генерации пакетов так же нуждается в поддержке. Я понимаю, что в идеале правильнее всего было бы сделать «идеального бота» — выбирающего рандомные направления и жмущего рандомные кнопки из числа осознанных комбинаций. И соответственно, советовать писать его с нуля молодому(как я думал) программисту — не надо.

Ну и в-последних: описанная мною фигнулька пишется часа за два-три в худшем случае… А вот с пакетогенераторам придется повозиться.

Вот где-то так вот.

Что я понял из статьи: "Мне было нечем заняться, так что я решил выбросить шмат работы и переписать сервер на Go, потому что там есть встроенный профилировщик".
Изначально у вас на Go получилось 20 клиентов, после профилирования 2500, то есть, на минутку, в 125 раз (!) больше.
Вы не думали, что осиль вы профилировщик на джаве, у вас бы могло выйти ~37500 клиентов? Ну, или даже если бы вышло 2500, что всего в 8 раз больше первоначального (с таким размахом в Go-коде я не удивился бы), усилий пришлось бы приложить заметно меньше.


Да, никогда от хороших java-разработчиков не слышал "ява".

Что я хотел сказать статьёй. «Написание определенных приложений занимает на go в несколько раз меньше времени и усилий чем на java. В том числе за счет более удобных инструментов.»
НЛО прилетело и опубликовало эту надпись здесь
Согласился бы. Но вот на java я пишу 18 лет, а на go к тому моменту не писал вообще.
Но на go таки вышло быстрее. Причем очень существенно.
НЛО прилетело и опубликовало эту надпись здесь
Продуктивность складывается из вашего опыта и знаний и удобства и мощности языка (в том числе, применительно к конкретной задаче).
Это легко можно увидеть на примере — человек X потратил много лет на изучение ассемблера.
У него стоит задача написания веб сайта.
Что будет для него эффективнее — писать сайт на ассемблере или на .NET?
Я думаю, .NET будет лучшим выбором.
Здесь я столкнулся с похожей ситуацией — увидел класс задач, который решается на go настолько удобнее, что несмотря на мой опыт на java я теперь предпочитаю для таких задач go.
НЛО прилетело и опубликовало эту надпись здесь
Но Go и Java суть одно и тоже, просто синтаксис разный.


Не соглашусь. Иначе не было бы смысла вообще создавать go.
Каждый язык имеет свои сильные и слабые стороны. Один хорош для одних целей, другой предпочтительнее для других. Каждый имеет свою нишу.
НЛО прилетело и опубликовало эту надпись здесь
Просто Google нужен был свой. Чтобы решать свои задачи.


Из этого можно сделать вывод, что есть какие-то задачи, для которых go подходит лучше других языков. (Ну или, что google таки создал его зря, как следует не разобравшись).
А раз так, значит go отличается от других не только синтаксисом.

Мне бы хотелось понять, что это за задачи.


Цитирую свою же статью: Какие задачи лучше всего решать на go? Создание многопоточных высоконагруженных серверных решений, в которых потоки много коммуницируют между собой.

Согласитесь, что в Java таких инструментов предостаточно?


Соглашусь. Предостаточно. Здесь речь скорее о философии языка. О том, что с точки зрения того или иного языка важно (а значит включено в набор стандартных инструментов, хорошо продумано и документировано) или просто есть (и, чаще всего создано третьими сторонами).
На любом современном языке можно сделать всё что угодно.
Разница в том, на чем язык предлагает сосредоточиться в первую очередь. В go профилирование и борьба с race conditions это, если хотите — first class citizens. В java — просто часть огромной экосистемы.
> Из этого можно сделать вывод, что есть какие-то задачи, для которых go подходит лучше других языков

Абсолютно корректный вывод. Такая задача одна, и эта задача — упростить найм (Гугл нанимает так много сотрудников, что профессионалов в этих количествах взять просто неоткуда). Иными словами вот таких «я тут потыркался в java, что-то не взлетело, ну так сейчас перепишем на го и заживем». Го спроектирован таким образом, чтобы даже баран не мог сильно напортачить, и это — его единственная цель (и плюс).

Сеньор в _любом_ другом языке решит _любую_ задачу лучше, чем на го. Джуниор на го решит любую задачу лучше, потому что ему язык надает по рукам в нужных местах. Но за все нужно платить: пока у вас не пятьсот тысяч сотрудников, го — обуза.
>>Что будет для него эффективнее — писать сайт на ассемблере или на .NET?
Подмена понятий.

>>Я думаю, .NET будет лучшим выбором.
Не верно, ибо подмена понятий.

Никто не пишет сайты на .net. Никто не пишет сайты на языке — сайты пишут на готовом апи. И без разницы какой это язык, если ты вызываешь какой-нибудь интерфейс. Разница только в сахаре, но это не особо принципиально, да в современных ассемблерах сахара не меньше.

Подлог заключается в том, что вы сравниваете пацана с .net, который на 99% состоит из готового веб-рантайма и пацана с асм, у которого рантайма нет. Но ведь .net-пацан этот рантайм не писал — точно так же асм-пацан может его написать, либо взять готовое.

Если же взять нормальное сравнение, а не изначально ущербное, то никакой разницы не будет.

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

А само явление заключается в том, что есть много языков программирования и раз каждый жив, значит у него есть ниша, где он лучше других.
В любой форме это сравнение не имеет смысла, ибо не является правдивым. Чистейшей воды подмена понятий «средства языка» с «готовые средства рантайма для реализации какого-то функционала». В данном случае в .net средства для веб есть по умолчанию, а у асм«а нет. И средства эти не уровня языка.

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

А далее уже удобство использования самого языка и чьи-то синтаксические предпочтения. Кому-то нравится $i, а кому-то нет. Кому-то нравится экосистема одного языка, а кому-то другого. В целом при равной мощи рантайма разница между языками в „запилить быстро и удобно“ мало различима.

>>значит у него есть ниша, где он лучше других.
Скорее наличие ниши и делает язык лучше, ибо он более специализирован, а не наоборот. И то не сам язык(в очень маленькой степени), а его рантайм/реализацию самого языка.

Лучше в смысле как язык, то тут не всё так просто. Лучше в одном — хуже в другом.
В данном случае в .net средства для веб есть по умолчанию, а у асм«а нет. И средства эти не уровня языка.

Можно предположить нереальную вещь: кто-то задался целью написать «сайт» (т.е. генератор страниц) на этих языках, используя только базовые библиотеки (доступ к сети через сокеты и доступ к диску). Тогда такое сравнение имело бы смысл.
НЛО прилетело и опубликовало эту надпись здесь
Очень спорный аргумент. Перевести приложение с одного языка на другой почти всегда проще, чем писать его с нуля.
Интересная статья, спасибо.
Довольно адекватно расписаны возможности языка. Однако Go для совсем новичков я бы никогда не рекомендовал, учиться программировать на Go гораздо тяжелее, чем на Java, в силу того, для чего он разрабатывался и какие задачи должен выполнять, имхо.
Однако Go для совсем новичков я бы никогда не рекомендовал, учиться программировать на Go гораздо тяжелее, чем на Java

Можно тут чуть подробнее? Почему «гораздо тяжелее»? Давно интересуюсь темой Go как первого языка программирования, и интересны мнения со стороны.
Go не прививает, скажем, правильное ООП, и подвержен некоторым крайне сомнительным практикам, например, хранение метаданных в комментариях или кодогенерации.
правильное ООП

Что это такое? И почему «неправильное ООП» сложнее новичкам, чем «правильное ООП».

крайне сомнительным практикам, например, хранение метаданных в комментариях или кодогенерации.

Принимаю аргумент про «сомнительные практики» — в других языках это действительно были хаки и сомнительные практики, но в чём проблема у новичков с этим?

Что это такое? И почему «неправильное ООП» сложнее новичкам, чем «правильное ООП».

Скажу проше. В Go — нет ООП. Go — это процедурный язык. И то, что в Go можно писать в ООП-стиле не делает его OOP языком. Аналогичная ситуация в Java, никто не назовет Java функциональным языком, но писать в таком стиле там можно. А как показывает практика, процедурников крайне сложно научить потом ООП.


Принимаю аргумент про «сомнительные практики» — в других языках это действительно были хаки и сомнительные практики, но в чём проблема у новичков с этим?

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

> как показывает практика, процедурников крайне сложно научить потом ООП

То есть, история вопроса нам как бы сообщает: в семидесятые годы прошлого века, когда мир вокруг состоял сплошь из процедурников, к нам явились марсиане и научили ООП. Так?

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

Справедливости ради, Алан Кей изначально вроде бы не думал о полиморфизме и наследовании как неотъемлемых свойствах ООП. Тема довольно размытая, поэтому категорично утверждать, что в каком-то языке нет ООП, а в другом есть — вряд ли конструктивно. Думаю, что «сильно отличается от повсеместно используемых практик» это максимум, что можно сказать, не рискуя уйти в холивар.


Вообще, есть ли смысл абсолютных новичков учить объектно-ориентированной парадигме? Если говорить вот прямо о людях с улицы, без курса CS за плечами, без какой-то IT основы. Мне кажется, что они будут тяготеть к процедурному стилю, обрушить на них объекты или функциональное программирования — у них сразу интерес пропадёт.

Вообще, есть ли смысл абсолютных новичков учить объектно-ориентированной парадигме?

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


Справедливости ради, Алан Кей изначально вроде бы не думал о полиморфизме и наследовании как неотъемлемых свойствах ООП.

Википедия, с ссылкой на книгу Т. Бадда (isbn 5887822708 в русском переводе) дает такой список правил, которые оговаривал Алан Кей:


  1. Всё является объектом.
  2. Вычисления осуществляются путём взаимодействия (обмена данными) между объектами, при котором один объект требует, чтобы другой объект выполнил некоторое действие. Объекты взаимодействуют, посылая и получая сообщения. Сообщение — это запрос на выполнение действия, дополненный набором аргументов, которые могут понадобиться при выполнении действия.
  3. Каждый объект имеет независимую память, которая состоит из других объектов.
  4. Каждый объект является представителем класса, который выражает общие свойства объектов (таких, как целые числа или списки).
  5. В классе задаётся поведение (функциональность) объекта. Тем самым все объекты, которые являются экземплярами одного класса, могут выполнять одни и те же действия.
  6. Классы организованы в единую древовидную структуру с общим корнем, называемую иерархией наследования. Память и поведение, связанное с экземплярами определённого класса, автоматически доступны любому классу, расположенному ниже в иерархическом дереве.

Тут есть наследование.

В чем принципиальная проблема нагуглить первоисточник, вместо каких-то «Вика сказала, что Бадд написал»?

✓ http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay_oop_en
✓ http://www.c2.com/cgi/wiki?AlanKaysDefinitionOfObjectOriented

Не было там ни полиморфизма, ни наследования.

Очевидно, от глупости, лени и не хватки времени.


Большое спасибо за первоисточник :)

С практической точки зрения — да, мотивация понятна: чтобы потом не переучивать для боевых задач. Я скорее говорю о ситуациии с людьми, которых в любом случае ещё рано закидывать в реальный проект — не интернов или джуниоров, а, скажем, детей, или просто впервые осваивающих программирование. Любопытно, есть ли тут кто-нибудь, кто детям преподавал. У меня очень маленький с этим опыт, будет нерепрезентативно.

Детский Scratch — учит Объектно-Ориентированному Программированию.
Детский Logo — учит Функциональному Программированию.
— и то и другое дети вполне понимают.

Лого вроде мультипарадигменный, нет? Тут скорее интерес с точки зрения опыта. Scratch — да, хороший пример.

Только если изначально считать ООП парадигму единственно верной. Более того, высказанный ниже тезис о «тяжести» перехода к ООП (если принять переход сам по себе за необходимость) требует какого-либо обоснования. Точно такой же аргумент применяют при обсуждении функционального п. («очень сложно тех, что начал изучать программирование с процедурных и ООП языков, научить ФП»).
Я правильно понимаю, что у вас был опыт наблюдения за новичком, который пытался начинать с go?
Если это так, расскажите подробнее, пожалуйста.
Я никаких проблем не вижу, но поскольку к моменту изучения go новичком не был, то мог что-то важное пропустить.
А вопрос для меня, действительно важный — думаю о более широком применении go в нашей компании.
В том числе и для юниоров.
НЛО прилетело и опубликовало эту надпись здесь
Спасибо. Интересный опыт. Хотя, данных для статистики недостаточно.
Вдруг это — особенность конкретного человека.
НЛО прилетело и опубликовало эту надпись здесь
Мне Go показался простым. Хотя привлёк не этим, а сдвигом «фокуса». Его авторы переосмыслили, что сегодня является важным в языке, а что — не очень. на мой взгляд, их вариант лучше подходит для решения актуальных задач.

А вот смог бы я осилить Go первым или нет — фиг его знает. Именно поэтому очень инетересен опыт тех, кто пробовал.

ему гораздо важнее решить задачу правильно, чем решить задачу в принципе.

Проблема в том, что у каждого своё — «правильно».
Для новичков будут проблемы в понятии самой концепции языка, не каждый новичок поймет как правильно выстраивать структуру приложения из интерфейсов и структур(хотя по мне так прикольная концепция вышла из этого). Потом Go-рутины, для новичка многопоточность это вообще страшная штука, которую просто так не понять с пары примеров, это куча опыта, которую и за год много не накопишь, новички не поймут пользы от многопоточности, Go-рутин, каналов и etc.

И приподносится этот материал по странному. В плане если в Java/C#/C++, когда разговор доходит о многопоточности первым делом говорится для чего это нужно и когда используется, в Go же это одна из основных концепций, и тем самым для совсем новичков это осложняет дело еще сильнее.

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

Если у человека есть опыт программирования даже просто в плане обучения на каком-нибудь Ruby/Python/Java, ему будет в этом разобраться будет не так уже тяжелее. Имел опыт общения с Go после C++, и в целом неплохо.
Go в целом язык ничего так, но не прям уж для запихивания во все дырки и не для совсем новичков. Это лично мое мнение.
Спасибо за четкую, и по делу статью.
Как вы думаете, Go ориентирован только на серверное использование, или на нем можно забацать приложение с окнами, графикой, и еще какими то финтифлюшками?
Сделать на go можно что угодно.
Мысль в том, что серверные многопоточные приложения быстрее и удобнее делать на go.
А для остальных особых преимуществ нет — дело вкуса.
Спасиб.
Имею некоторый опыт работы с java, поэтому статья очень в тему.
Открой для себя JNI
Зачем?
Но ведь это не жава? С таким же успехом можно писать на си и вызывать из го, не?
Статья не об этом. Она о продуктивности разработчика.
А мне показалось, что вы уперлись в потолок производительности и решили поменять инструмент. Пойду перекрещюсь.
Для решения этой проблемы используются внешние инструменты — менеджеры пакетов.
Один из лучших на сегодняшний день — glide.

Зачем использовать стороннюю утилиту, если данная проблема уже решена на уровне языка — используйте директорию vendor (v1.5 experimental, v1.6 default)
Кстати, директория vendor решила и ещё одну проблему о которой вы не упомянули, локальные импорты.
glide её использует
Просто он позволяет не хранить сторонние пакеты в своей системе контроля версий.
Каждый член команды может при помощи glide поместить в свою директорию vendor нужные версии сторонних пакетов.
Судя по приведенным аргументам, все-таки остается впечатление, что выбор сделали скорее эмоциональный, нежели рациональный. Новый язык всегда изучать весело.

Если требуется поддерживать несколько тысяч клиентов одновременно, особенно при высокой частоте запросов как в онлайн игре, понятно что скорее всего придется использовать асинхронный ввод-вывод вместо традиционной модели «один поток на соединение». Тут, как говорится, и к гадалке (профайлеру) не ходи. Да, в Го это работает из коробки путем использования «горутин», ну а в Java можно использовать Netty.

Проблема с запуском профилировщика удаленно в Java совершенно надумана. Достигается добавлением пары опций в JVM.

Проблема с запуском нескольких тысяч клиентов тоже надумана. Зачем запускать настоящие клиенты, если можно с помощью того же Netty/NIO написать относительно несложную программу для нагрузочного тестирования, которая буквально с одного компьютера создаст достаточную нагрузку?

И в конце концов, в Го вы все равно можете упереться в сборщик мусора или, скажем, странное поведение планировщика горутин. И что тогда, снова все бросить и переписать на C++?

По-моему, шило на мыло. Выбросили существующий код и проверенную временем JVM ради «модного» языка из-за каких-то странных доводов.
> а в Java можно использовать Netty.

Или VertX или Play или много чего еще.

> Проблема с запуском профилировщика удаленно в Java совершенно надумана.

Тут вы правы. Я неверно расставил акценты. На самом деле надо было сказать о простоте и удобстве работы со штатным профилировщиком go. По мощности он превосходит VisualVM и сравним с YourKit. По удобсвту работы — лучшее, что я видел вообще. Экономит много времени.

> написать относительно несложную программу для нагрузочного тестирования

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

> в Го вы все равно можете упереться в сборщик мусора

Да. Его пришлось отключить вовсе. Точнее перевести в ручной режим. Сначала код был переписан так, чтобы минимизировать использование кучи. Потом автоматический gc был отключен и заменен на код, который запускает его вручную, если свободной памяти на сервере осталось немного. Перед таким ручным запуском все клиенты принудительно ставятся на паузу. Происходит это редко и для игрока такое поведение много луше частых небольших лагов.

> Выбросили существующий код и проверенную временем JVM ради «модного» языка из-за каких-то странных доводов.

Ради опыта. Я знал сколько времени занимает решение подобной задачи на java. Я подозревал, что на go потребуется меньше. Я убедился, что да, меньше. Раза в два. И теперь я буду решать такие задачи на go и экономить свое время.
Этим вот опытом и поделился.
Или VertX или Play или много чего еще.
Ну странно наличие вариантов рассматривать как минус. Так же можно было вместо Го использовать Rust, node.js или много еще чего.

Я подозревал, что на go потребуется меньше. Я убедился, что да, меньше. Раза в два.
Верю с трудом, особенно в долгосрочной перспективе, и тем более если есть опыт подобных проектов на Java.

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


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

Верю с трудом, особенно в долгосрочной перспективе, и тем более если есть опыт подобных проектов на Java


Здесь сложно что-то возразить. У меня оно было так. Но каков в этом результате вес самого языка, моего проекта и моих личных предпочтений мне сказать трудно. Если есть опыт разработки таких проектов на java и если вас не раздражают VisualVM или YourKit, то, возможно, у вас будет другой результат.

Единственное, на чем я настаиваю — если взять двух новичков и один станет изучать java + экосистему, а второй go, то проект, подобный моему, быстрее получится у второго при прочих равных.
Наличие вариантов имеет свои минусы (порог вхождения) и плюсы (можно подобрать наиболее оптимальный).
Если говорить о продуктивности разработки, то наличие ровно одного хорошего способа сделать что-то будет плюсом, так как сэкономит время.
Отсутствие альтернатив во все времена приводило к монополии. Наличие конкурентов/альтернатив вынуждает авторов библиотек совершенствовать свои продукты.

Единственное, на чем я настаиваю — если взять двух новичков и один станет изучать java + экосистему, а второй go, то проект, подобный моему, быстрее получится у второго при прочих равных.
А если взять профессионала, то тот выберет java, так как на ней лучше писать долгоживущие проекты?
Отсутствие альтернатив во все времена приводило к монополии. Наличие конкурентов/альтернатив вынуждает авторов библиотек совершенствовать свои продукты.


Вы привели еще один плюс наличия альтернатив. Только он не имеет отношения к продуктивности разработчика здесь и сейчас.

А если взять профессионала, то тот выберет java, так как на ней лучше писать долгоживущие проекты?


А если взять профессионала, тот изучит проект и будет выбирать инструмент исходя из требований.
«я слепил чего-то там на java и оно держало всего 300 коннектов, переписал на go — стало держать 2.5к» (с)
Ничего не имею против Go, но давайте поговорим о Ваших опытах с Java.
Есть куча суццесс стори задач схожих с вашей — сверера для мультиплеерных игр. Возьмем на пример Riot Games и их League of Legends, где на секундочку, онлайн в пики достигает 5 миллионов юзеров. Понятное дело там у них маштабирование и прочее, но если бы у них сервер держал 300 коннектов, то никаких денег бы не хватило, будь Ваши слова хотя бы отчасти правдой.

Если уж Вы пытаетесь продвинуть мысль того, что go производительнее java в разрезе вашей задачи, то пишите подробности реализации, сравнения, бенчмарки в конце концов. Насколько мне известно, Netty вообще одна из самых производительных штук в разрезе данного юзкейса и сдается мне, что Вы либо писали свои костыли либо просто не умеете в Netty…

Из всей статьи полезный и осмысленный только вывод…
Если уж Вы пытаетесь продвинуть мысль того, что go производительнее java в разрезе вашей задачи


Вы неправильно поняли. В разрезе моей задачи производительнее не go, а программист, пишущий на go.
Он справится с такой задачей быстрее, даже если ранее имел опыт программирования на java и не имел на go.
Т.е. в конторах пишущих игры ААА класса сидят дурачки, которые не знают, о том что программист на Go производительнее программиста на Java?! Тогда уж «в разразе Вашей задачи Вы пишущий на Go произовдительнее себя же пишущего на Java».
Т.е. в конторах пишущих игры ААА класса сидят дурачки, которые не знают, о том что программист на Go производительнее программиста на Java?!


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

в разразе Вашей задачи Вы пишущий на Go произовдительнее себя же пишущего на Java


Если говорить совем строго, то да. Именно так. Но я рискну расширить это утверждение до следующего «в разразе моей задачи человек с 18летним опытом программирования на java и нулевым опытом на Go, пишущий на Go произовдительнее себя же пишущего на Java»
человек, который 18 лет разрабатывает на java и не знает о существовании возможности удаленного подключения профилировщика, вызывает подозрения
Вы то точно разрабатываете на java со вчера и уже знаете абсолютно все, мы не сомневаемся =)
Сомнения — признак критического мышления, а то, в свою очередь, признак здравомыслия
Вы правы. Не пойму, как я написал такое. На эмоциях, наверное. Очень раздражает меня VisualVM. Трудно найти что-то более неудобное.
Согласен с тем, что не всё в мире java идеально и в эпоху перемен хочется свежего воздуха, я и сам внимательно смотрю на котлин. Здорово, что этот глоток свежего воздуха пришелся вам по душе, но все-таки статья скорее эмоциональный выплеск об этом, нежели что-то полезное в техническом смысле. Было бы интереснее, если бы вы описали какие аналогичные средства вы использовали в обоих реализациях и что именно было удобнее, возможно рассказать об архитектуре серверной части игры, а такой холиварный формат неизбежно вызывает раздражение у читающих
Это всё от лени. Я просто взял и опубликовал собственный рассказ на корпоративном семинаре.
По уму для хабра статью надо было перделать и писать примерно так: Вот уже 14 лет мы пробуем новые языки, чтобы не пропустить технологическую волну. До сих пор, ни один язык не выигрывал у явы в главном для нас параметре — в скорости разработки. Так было, пока не появился go.
Этот самый go выиграл по этому параметру на таком-то проекте. Если ваш проект похож, обратите внимание на go.
Тогда бы и холивара было бы поменьше.
Холивара было бы поменьше, если такие статьи (саксес стори) по Go были более объективными.
А так они все как под копирку. Одни досужие домыслы и притягивания за уши. Без какой либо конкретики.
Добавьте сюда, по вкусу: вранье, передергивание или откровенное нубство в сравниваемой технологии (в данной статье про Java).
И получите типичный холивар.
Напишите нормальную статью. С примерами похожих задач.
Вот так делали на Java (и это должен быть реальный пример на современных подходах и библиотеках).
А вот так мы сейчас делаем на модном Go.
С описанием и цифрами. Что улучшилось в процессах. Что улучшилось в коде. Что там с багами и поддержкой. Что с рефакторингом и т.д.
Все вам огромное спасибо скажут.
А то вот таких вот домыслов «вилами по воде» в каждом бложике миллион.
Они ничего не улучшают, а только хуже делают.
Ибо оставляют больше вопросов, чем дают ответов.
А в отсутствии реальных фактов, люди начинают сплетничать и фантазировать на тему как оно там может быть…
Вы пишите о вранье, передергивании и нубстве и тут же требуете цифр, примеров и фактов.
Допустим я скажу, что аналогичная задача на яве заняла у меня X дней, а на go — Y (где Y<X), вас это убедит?

На самом деле, каждый приведенный факт можно поставить под сомнение. Кажды новый факт будет лишь разжигать холивар.

Проблема совсем не в фактах, а в неаккуратном позиционировании моей статьи. Многие тут посчитали, что я хвалю go и ругаю java, приводя в качестве (слабого) аргумента некую сомнительную, как вы сказали «success story». Я сам дал повод так понять эту статью неаккуратной расстановкой акцентов.

Где-то уже писал, что статья не про то. Она про: «ребята, смотрите, go гораздо менее требователен к вашему времени и усилиям по крайней мере на некоторых видах задач. Если ваши задачи схожи, то Go стоит попробовать. Возможно, вы получите некоторый profit.»

Оставьте цифры. Дайте пример с кодом или описанием архитектуры на Java и, соответсвенно на Go.


Без этого создается впечатление именно нубства (может это и не так) из-за 300 клиентов, неспособности запустить профайлер, а также довольно спорного описания самого языка. О проекте при этом ни слова кроме того, что у вас получилось на Go лучше чем на Java.

Вы хотите от меня доказательств заведомо ложного тезиса вида «На java нельзя создать такой же быстрй сервер, как на go». Можно. Я думаю, он даже будет поддерживать несколько бОльшее количество клиентов.
Я утверждал лишь, что создание такого сервера на go занимает меньше времени и сил.
Как наличие (плохого) кода на java и хорошего на go может подтвердить или опровергнуть моё утверждение?
Я утверждал лишь, что создание такого сервера на go занимает меньше времени и сил.

Есть разница между "на Go разрабатывать проще и быстрее, чем на Java, благодаря дизайну языка" и "на Go разрабатывать проще и быстрее, чем на Java, потому что я плохо знаю Java". Вы демонстрируете именно второй случай, а он мало кому интересен.


Как наличие (плохого) кода на java и хорошего на go может подтвердить или опровергнуть моё утверждение?

Наличие (хорошего) кода на обоих языках подтвердило бы, что речь именно о языках, а не о ваших способностях.

на Go разрабатывать проще и быстрее, чем на Java, потому что я плохо знаю Java


А go не знаю совсем. Это не меняет дело?

Наличие (хорошего) кода на обоих языках подтвердило бы, что речь именно о языках, а не о ваших способностях.


Но у меня нет хорошего кода на ява, который делает то же самое. Он мне не был нужен.
А go не знаю совсем. Это не меняет дело?

Меняет. Превращает посыл статьи в "нубы, перебирайте языки пока вам не повезет состряпать удачную архитектуру на одном из них". Если бы у вас и на Go ничего не вышло, вы пошли бы дальше? И мы читали бы статью «ребята, смотрите, C# гораздо менее требователен к вашему времени и усилиям по крайней мере на некоторых видах задач. Если ваши задачи схожи, то C# стоит попробовать. Возможно, вы получите некоторый profit.»

Я просто не вижу смысла спорить с вами о своём профессиональном уровне.
По двум причинам. Во-первых, вы уже все для себя решили, а во-вторых меня не интересует профессиональное мнение человека, который родился в тот год, когда я написал свой первый профессиональный код — часть АСУТП для Сургутской ГРЭС.

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

Это я на случай, что кто-то почитает комменты и согласится с вашим посылом про «нубы, перебирайте языки...» только потому, что я ничего не возразил.
О, пошел в ход возраст. Это много говорит о вас.

P.S. Это случайно не та самая ГРЭС где 2 раза крупные аварии были? Совпадение? ))
> Допустим я скажу, что аналогичная задача на яве заняла у меня X дней, а на go — Y (где Y<X), вас это убедит?

Вы вообще не понимаете, что такое «объективность» чтоли?

>ребята, смотрите, go гораздо менее требователен к вашему времени и усилиям по крайней мере на некоторых видах задач.

Менее требователен по сравнению с чем? Как сравнивали, чем мерили и т.д.
Эта фраза и есть «досужие домыслы».
Вы даже поправляя «позиционирование» статьи, лучше не делаете. Даже в этих каментах вы не понимаете, что делаете и продолжаете разжигать холивар на ровном месте.
Если честно, я долго пытался понять, шутка это или нет (я про статью). У нас многие игровые сервисы на Java в связке с netty. Оно у меня без особых проблем тысячи коннектов держит.
Видимо я нечетко расставил акценты — очень много одинаковых комментариев.

Шутка не в том, что java будто бы медленнее. Шутка в том, что решение моей задачи занимает у программиста go намного меньше времени.
С учетом того, что большинство по рассказу выявило в вас профана в java, то да, это конечно очень объективно.
Откройте для себя Akka (она кстати поверх Netty работает), там создать сервер слушающий TCP/UDP/Web-soket'ы — это дело пары минут. Там вам и прозрачная модель работы с многопоточнотью, и обсолютно никаких блокировок, и поддержка кластера «из коробки» и еще куча плюшек.
Мне лично Go тоже нравится, игрался с ними недельку после рекомендации знакомого, но для себя не нашел не одного плюса относительно тех задач, которые мне приходится реализовывать на Java, темболее последний год с небольшим работаю со Scala — тут даже сравнивать бесмысленно.
Akka, как и Play — реально хорошие вещи.
Но у меня стояла другая задача. Я хотел проверить гипотезу о том, что на go решение этой задачи потребует меньше усилий, чем на java.
Зачем мне это надо? Потому что мне, как владельцу IT компании, важно не пропустить технологическую волну. Не оставить свою команду работать с устаревшими, неэффективными технологиями и не уступить рынок другим, более шустрым игрокам.
За последние 14 лет ни один из новых языков не дал существенного прироста в производительности. Go оказался первым.
Добрый день. На мой взгляд для вашей задачи так же хорошо подошел бы Erlang. Вы рассматривали Erlang?
Рассматривал. Но мой мозг отказывается писать на нём сколько-нибудь большой объём кода.
Хотя его концепции мне понравились.
> Akka (она кстати поверх Netty работает)
Чушь полная. По верх Netty работают как раз примеры которые привел автор: VertX и Play.
Что лишь в очередной раз показывает в нем профана в Java мире.
В Akka же по верх Netty работает только кластер. Т.е. обмен данными между нодами.
И то это выпилят постепенно. Т.к. в Akka уже есть своя отличная реализация сокетов, модуль Akka.io.
Да, в курсе того, что Netty как депенденси только в remote (а cluster в свою очередь от remote зависит). И про то, что они постепенно от нее избавятся тоже слышал (толи в gitter'е, толи на одной из конференций кто-то упоминал). Просто хотел упомянуть этот факт, надо было сразу уточнить.
Кстати, а разве Play в свою очередь не делает потуги в сторону того, чтобы полностью заменить Netty на Akka? По крайней мере где-то упоминалось, что они планируют, если я не ошибаюсь.
Команда Play пробуют akka-http. Но так как Akka-http еще experimental, и с производительностью там еще не так все гладко, видимо попоробовав — поймут, стоит ли выпиливать netty.
Спасибо, интересная статья!
Если без чего-то можно обойтись, без этого нужно обойтись.

То есть обеспечение безопасности конкурентного доступа на уровне типов — лишняя возможность, а форматировние на уровне языка — жизненно необходимо?


Код на go на 20-30 процентов короче аналогичного на яве

А обработка ошибок приводит к большому количеству однотипного кода.

Взаимоисключающие параграфы.


Достаточно, чтобы у сущности просто были все нужные методы.

Это называется "структурная типизация".


Горутины можно мыслить как задачи, выполняемые одним общим большим тред пулом

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


Канал в go это очередь (буфер) в один конец которого можно писать, а из другого читать.

Это называется "блокирующая очередь". Везде реализуется на уровне библиотек.


можно указать как локальное имя, так и адрес пакета в любой современной системе контроля версий (например, в git)

Bazaar поддерживается? Svn?


В go пошли дальше и сделали поддержку управления зависимостями на уровне самого языка.

Для решения этой проблемы используются внешние инструменты — менеджеры пакетов.

Без такой неполноценной поддержки тоже было не обойтись?

НЛО прилетело и опубликовало эту надпись здесь

Имелось ввиду везде, кроме го. :-)

Я не понимаю удивления автора когда он постоянно указывает на прирост в скорости разработки местным комментаторам, но в статье привел цифры прироста производительности.
Товарищ автор, мы программисты(и немного математики) акцентируем свое внимание в первую очередь на цифрах а не на воде что выше.
Все ваши размышления о инструментарии это просто вода, потому что мы о вас и вашем проекте вообще ничего не знаем:
1. Каков опыт разработки на Java, сколь сложные проекты писали до, использовали ли либы которые нужно было использовать в вашей задаче(Netty, Akka, Quasar)?
2. Приведите пример(а лучше несколько) кода на Java и затем тот же код(или ту же часть логики) на Go(идеально ту часть кода которая тормозила и которую смогли оптимизировать).
3. Какие другие языки рассматривали? Их сейчас много это и Rust, Nim, Elixir, да и NodeJS достаточно производителен, Scala или Kotlin на JVM на которых можно супер короткий и производительный код писать.
А еще есть прикольный http://www.ponylang.org/(не рекламы ради просто для разнообразия).
Обычно при переходе на другой язык рассматривают несколько вариантов, и делают некоторый анализ.
4. Приведите хотя бы цифры для разработки, например сколько дней у вас ушло на написания кода на Java и сколько на переписывание на Go. Это важная информация в контексте вашего постоянного уточнения.
Как бы вы отнеслись к статье, которая бы начиналась рассказом об авторе его опыте и личных достижениях?
Думаю, большинство комментаторов уместно поинтересовались бы — чего это автор тут пиарится, вместо того, чтобы говорить дело.

Смысл статьи коротко можно выразить так — «Люди, смотрите, есть такие задачи, которые на go получается решать намного быстрее, приятнее и эффективнее, чем на java. Будет свободное время — гляньте сами. Время окупится.»

Проект был всего лишь иллюстрацией. Но если вы, или кто-то другой действительно интересуетесь этим проектом, я отпишу тут подробнее.
Как можно интересовать тем, чего нет? Вы так и не сформировали чёткой иллюстрации/описания вашего проекта. Поэтому сейчас он не может быть интересен сам по себе. А вот как источник дополнительной информации, которая поможет дать оценку «а стоит ли верить автору» — очень даже.
Пока что никаких доказательств ваших слов никто не увидел. Вопрос доверия — так же решается не в вашу пользу (у вас нет «кредита доверия» — вас никто не знает).
Вы так и не сформировали чёткой иллюстрации/описания вашего проекта.


Потому что статья была не о проекте.

Пока что никаких доказательств ваших слов никто не увидел.


Что бы вы посчитали доказательством моих слов?

у вас нет «кредита доверия» — вас никто не знает


Да, это так. Это было частью эксперимента. Мне нужен был честный фидбэк на статью, а не на статью, которую написал «авторитетный чувак».
Я его получил. Теперь я лучше понимаю как надо и как не надо писать статьи на Хабр.
Полезный опыт.
Принцип простоты звучит так:
Если без чего-то можно обойтись, без этого нужно обойтись.

Это как? Это как в C++ нет ни Юникода, ни нормальной работы со строками? Или что под этим подразумевается?
«Go можно выучить за 2 вечера» стоит отметить, что это это сильно зависит от предыдущего опыта. У меня как у быдлокодера с основным опытом на node.js подробное изучение языка заняло больше времени, т.к. появляется куча новых понятий.
Очень интересная статья, язык Go определённо стоит как минимум внимания. Благодарю за материал.
> После работы с профилировщиками эта цифра выросла до 2500.
А как получена эта цифра?
Путем запуска нагрузочных тестов и измерения используемых ресурсов сервера.
Дополнительно запускался и «нормальный» клиент для субъективной оценки поведения игры под этой нагрузкой.
Напишите, как Вы шутер делали. Было бы интересно почитать.
Ну это только после релиза.
Хех. А у меня сервер на java держит 10к клиентов на одном виртуальном ядре за 5$ на DigitalOcean. Давайте все на яву назад переходите :).
Я не понял, а где циферки-графики, как было «плохо» на java и как «хорошо» стало на go? Было 20, стало 2500 — весьма размыто…
У Вас, батенька, что-то с архитектурой не так, а не у java проблемы.
НЛО прилетело и опубликовало эту надпись здесь
Java не тормозит. Тормозил мой неоптимальный код и неверно выбранная серверная библиотека.
Обычно в таких случаях берутся (неудобные) инструменты (VisualVM, например), слабые места изучаются и оптимизируется.
Но в этот раз мне попалась статья об аналогичных инструментах в Go.
Мне показалось, что инструменты настолько превосходят java аналоги, что результат будет достигнут намного быстрее.
Так оно и получилось.
«на одном виртуальном ядре за 5$ на DigitalOcean» серверок на java генерит ответ минимально за 85 μs, на Go та же функциональность — 9 μs.
Даже «простые» единичные запросы к БД на Go быстрее в 2-3 раза, по сравнению с java
Есть масса обратных примеров.
Статья не о скорости языка, а о скрости разработки на языке.
У меня есть совершенно другие цифры: вытаскиваем сущность из 12 полей, маппаем в DTO объект, сериализуем в json: ~15ms. Ах да, там еще jwt токен декодится(HmacSHA512) и мапается из json-строки в объект. Стек: Akka HTTP 2.4.8, Slick 3.1.1, Spray Json 1.3.2. Если пооптимизировать и «прогреть», то будет еще шустрее. (это не Java, а Scala, но какая разница если ранается под JVM).
А Ваши цифры и выводы без информации о том как и на чем было написано не нужны никому… Если уж хотите поевангелировать Go, то делайте это нормально. А то одолели уже эти околохоливаные посты/комменты гоферов и постоянный наброс на вентилятор.
Забыл упомянуть: БД — PostgreSQL. Обычный JDBC драйвер(есть просто postgresql-async, возможно он быстрее), для пула коннектов — HikariCP. Никаких доп флагов для JVM не выставлял.
>>Потом появились треды (или нитки). Они были гораздо легче и работали в одном адресном пространстве. Если процессов обычно запускали единицы или десятки, то тредов можно было иметь уже сотни.
И какое отношение «было» имеет к сейчас и к го?

>>Однако, при неаккуратном использовании и они могли отнять все ресурсы системы.
Не могли. Никогда.
>> Каждый тред всё-таки занимал какие-то ресурсы, даже если был заблокирован.
Не занимал, а занимает. При этом точно так же он занимает в го, при этом это «занимает» ничего не занимает в сравнении с оверхедом ГЦ.

>>Чтобы ограничить число тредов, начали использовать тред пулы.
Не верно. Тредпул, если это именно тредпулл с постоянно живущими потами — существует не для это. Он существует для нивелирования оверхеда на запуск потока.

>>Горутины можно мыслить как задачи, выполняемые одним общим большим тред пулом. В Go горутины крайне дешевы.
Го тут непричём — го лишь одна из реализаций юзерпейс «тредов». И при этом «дешевы» — это не верно.

>>Вы можете запустить миллионы горутин без проблем для производительности.
Если под производительностью имеется ввиду как во всех бложиках «спящие треды не отъедают производительность» — это точно так же работает и в системных потоках.

>>Единственное требование — горутины должны быть «маленькие».
Не да, чтобы не надо было шедулить много активных горутин. Типичное проявление слабости шедуллера.

Я уже слышал столько легенд об «тормазящих системных потоках, которых нельзя запустить больше 20», «запустил 100системных потоков и даже спящие съедят 100% цпу» и прочее.

Но проблема как всегда в том, что когда адептам рассказывают что-то про «горутины вс системные треды» — почему адепты никогда не требуют доказательств? Сколько бы я не гуглил — я не увидел ни единого бенчмарка, либо сравнения с системными тредами.

Берём пишем простой бенч — создаём 100500(линукс больше не может, вернее он там и больше 30к активных не может) тредов с телом «инкремент атомика», а после смотрим за сколько все эти 100500 тредов отработали.

package main

import "fmt"
import "sync/atomic"

func main() {
    var ops uint64 = 0
    var n = 100500;
    for i := 0; i < n; i++ {
        go func() { atomic.AddUint64(&ops, 1) }()
    }
    for atomic.LoadUint64(&ops) < uint64(n) {}

    fmt.Println(atomic.LoadUint64(&ops))
}


#include <thread>
#include <vector>
#include <atomic>
#include <cstdio>


int main() {
  std::atomic<size_t> c{0};
  size_t n = 100500;
  
  for(size_t i = 0; i < n; ++i) std::thread{[&](){++c;}}.detach();
  while(c < n) {}
  fprintf(stderr, "%lu\n", (size_t)c);
}


pthreads
100500

real 0m0.288s
user 0m0.040s
sys 0m0.250s


Go
100500

real 0m0.226s
user 0m0.340s
sys 0m0.010s


В конечном итоге мы видим, что го еле-еле на 30% быстрее. При этом эту разницу можно выкрутить почти в ноль, если затюнить pthread/ведро.

Ну и так же мы видим, что создание даже 100500 тредов, которые ничего не делаю нихрена не «бесплатно», а даже очень платно.

Если же впилить в С++ слипы в каждый тред, то оно отработает так же(правда надо уменьшить количество до 30к, иначе падает с «кончились ресурсы»). Если же впилить в го — оно встанет раком. Может я просто не так писал слипы в го?

К
Если же впилить в го — оно встанет раком. Может я просто не так писал слипы в го?


package main

import "fmt"
import "sync/atomic"
import "time"
import "sync"

func main() {
    var ops uint64
    n := 100500
    var wg sync.WaitGroup
    wg.Add(n)
    for i := 0; i < n; i++ {
        go func() { atomic.AddUint64(&ops, 1); time.Sleep(1*time.Second); wg.Done() }()
    }
    wg.Wait()

    fmt.Println(atomic.LoadUint64(&ops))
}


Вывод:
100500

real 0m1.289s
user 0m0.978s
sys 0m0.105s


n := 1005000

Вывод
1005000

real 0m3.618s
user 0m9.097s
sys 0m0.671s


n := 1005000
time.Sleep(0*time.Second)

Вывод
1005000

real 0m0.236s
user 0m0.574s
sys 0m0.008s
Т.е. я не могу просто что-то запустить в мейн-потоке? Почему? Какие для этого есть причины?

По поводу вашего кода — вайл там не столько для ожидания завершения, сколько эмуляции нагрузки на основной поток.
Можно. Именно прямо ваш код:
real 0m0.027s
user 0m0.057s
sys 0m0.004s


Именно ваш с миллионом горутин
real 0m0.238s
user 0m0.548s
sys 0m0.012s


С миллионом горутин и паузами (*)
1005000

real 0m2.446s
user 0m5.839s
sys 0m0.714s


// * но для равноправия потоков заменить
for atomic.LoadUint64(&ops) < uint64(n) {}

// на это
var wg sync.WaitGroup
wg.Add(1)
go func(){
	for atomic.LoadUint64(&ops) < uint64(n) {}
	wg.Done()
}()
wg.Wait()
Можно.

но для равноправия потоков заменить

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

Именно ваш с миллионом горутин

Какие-то невероятные результаты. Скорее всего там 100к горутин.

С миллионом горутин и паузами (*)

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

Какие-то невероятные результаты. Скорее всего там 100к горутин.

Да. Ошибся. С миллионом выходят ~2.5сек.

Надо определиться.

Первые два примера только ваш код (во втором случае разве что n увеличено в 10 раз). Никаких больше правок.

Изменение коснулось только последнего примера со слипами.

Правда выжирает оно 2.5 ядра, что в 2.5 раза медленее птредов
pthreads
real 0m0.288s
sys 0m0.250s
Go
real 0m0.226s
user 0m0.340s


У вас C++ сидел в ядре (обрабатывая 100500 потоков), а Go в юзерспейсе (100500 горутин на 4-8(?) потоков). При этом Go съел чуть больше проца, но и завершился чуть быстрее.

Кстати, вот про шедулинг горутин (хоть и не самый свежий), реализацию стека и прочую начинку:
https://habrahabr.ru/company/ua-hosting/blog/269271/
https://habrahabr.ru/company/mailru/blog/283038/
https://habrahabr.ru/post/276255/
https://habrahabr.ru/company/intel/blog/275709/
Первые два примера только ваш код (во втором случае разве что n увеличено в 10 раз). Никаких больше правок.

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

У вас C++ сидел в ядре (обрабатывая 100500 потоков)

Ну он не только в ядре сидел. Он сидел 100500 раз в ядре и 100500 раз в юзерпейсе.

При этом Go съел чуть больше проца, но и завершился чуть быстрее.

Ну если в этих горутинах будет не инкремент атомина, который на фоне всего стоит в районе нуля, а что-то посерьёзней, то быстрее они уже не завершатся.
>оно не завершается пока все горутины не завершены, даже если я их не жду, что странно.
Какие-то горутины не могут получить управление, чтобы отработать, потому цикл ожидания никогда и не завершается.
Добавьте runtime.Gosched(), как вам уже советовали.

> а что-то посерьёзней, то быстрее они уже не завершатся
Как бы разница в пользу Go не стала выше из-за отсутствия переключений ядра и юзерспейса.
Какие-то горутины не могут получить управление, чтобы отработать, потому цикл ожидания никогда и не завершается.

Ещё раз. Меня не интересует как сделать так, чтобы это работало. Меня интересует то — по какой причине это не работает так, как написал я.

Добавьте runtime.Gosched(), как вам уже советовали.

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

Как бы разница в пользу Go не стала выше из-за отсутствия переключений ядра и юзерспейса.

Опять же ни на чём не обоснованные утверждения. На основании чего там станет переключений больше? Потому что кто-то сказал?

Ну и для справки — переключение ничего не стоит. Особенно на фоне всплывших подробностей работы горутин с сисколами. Как будет время — я напишу бенчмарки с сисколами и добью эту тему. Другой оратор уже поплыл — до подробностей кричал «горутины аналог мультиплексинга», а после уже «надо юзать горутины с епулом, который собственно их аналогом и является. Бывает.

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

Не «надо юзать», а «библиотека Go под капотом юзает». Это и есть мультиплексинг. А вообще, firsttimecxx, завязывайте с таким тоном. Вам тут никто ничего не обязан, в том числе по десять раз объяснять всё, что все остальные давно уже поняли или с самого начала знали. Вы не понимаете, что такое мультиплексинг? Не знаете, что такое event loop? Не знаете, как работают async/await? Бывает. Жизнь — процесс познания нового. Только хамить не надо.

Не «надо юзать», а «библиотека Go под капотом юзает». Это и есть мультиплексинг.

Это не ответ. Ещё раз, меня никаким тоном пугать не надо. Меня это мало волнует.

Хорошо, раскатывать — так раскатывать.

Утверждение раз:
Это не совсем аналог потоков в других языках, это скорее аналог futures, promises, async/await, libevent и подобных вещей.


Суть — противопоставление мультиплексинга(libevent) и горутин.

Утверждение два:
Там, где в го используются горутины, в C вы обычно используете libevent а не потоки.


Противопоставление горутин и мультиплексинга — два.

Далее, когда оратор был зажат в угол — последовало:

Но вы можете сделать иначе — вы можете использовать событийную модель. Горутина может вызвать собственную сетевую библиотеку, а та, обёртывая системные вызовы, добавляет сокет в список ожидания epoll(). При этом заблокируется только один поток на все сокеты.


Опустим событийную модель — она тут не при делах и я не буду это разоблать, что epoll не про событийную модель, но это такое.

Чтобы оратор опять не поплыл с моделью использования горутин — уточним:

Миллион одновременных клиентских соединений? Это чуть ли не канонический use case. Живут, что-то считают, засыпают на ввод-вывод, снова просыпаются, умирают.


Суть — поток данных клиент/сервер находится в своём потоке(выполнения). Это юзкейс для горутин, что собственно выше я и писал.

Далее, мультиплексинг — это про сбор множества потоков данных в один поток, который обрабатывает уже один поток(выполнения) и нет смысла использовать для этого множество потоков(выполнения).

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

Далее пошла типичная тактика обвинять меня в том, что я чего-то не понимаю и он видите ли мне что-то объясняет, а я не понимаю.

Такую же тактику использует адепт ниже, только он на вопрос «почему не работает?» — отвечает «вставьте кастыль — заработает», и каждый раз утверждает, что он отвечает.

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

Жизнь — процесс познания нового. Только хамить не надо.

Просто смешно. Может мне спросить основание для обвинения меня в " Вы не понимаете, что такое мультиплексинг? Не знаете, что такое event loop?"? И будет очередное «поплыл»?

Ну и конечно же хамить. Это любимое занятие слабой аудитории — сливаться на «хамить» и прочее. А на вопрос «где я хамил» — обвинитель ничего показать не может, а если и может, то связать цитату и «хамил» логически не может.

Это я ещё не начал разоблачать " с самого начала знали." и сливы вида «итак было ясно, что системные потоки не медленнее». Это делается очень просто — я ищу на хабре все статьи про го, в которых упоминается «быстрее» написанные после вышей регистрации и если там не будет в ответах опровержения от вас, либо найду у вас цитатку подобную.

«Тактика», «адепт», «раскатывать»… в странном мире вы живёте. Извините, но еда — всё. Спасибо за диалог.

«Тактика», «адепт», «раскатывать»… в странном мире вы живёте.

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

Люблю эту адиторию. Много из себя строит, а после первых трудностей сбегает.

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

Но иногда бывает так, что тот кто спрашивает — спрашивает это не для того, чтобы ему объяснили. А для того, чтобы адепт на кураже выложил все свои представления о теме. А далее эти представления очень просто разбиваются.

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

Если вы на 4х ядрах без вытесняющей многозадачности запустите 4 cpu-bound потока, а потом захотите запустить 5ый, но он не будет выполняться, — это тоже дыра в дизайне? Больше похоже на неправильное использование.

Вы ставите задачи шедулеру, но не даете ему работать. Вам это уже писали.

На основании чего там станет переключений больше

Потому что нет постоянных переключений огромной кучи потоков. Каждый поток (а их мало, единицы) имеет свою очередь горутин на выполнение, и просто их выполняет по очереди, не покидая юзерспейс.

P.S. Если так хочется посравнивать, можете сделать просто два распараллеленных cpu-bound теста рассчетов на хотя бы 10к горутин и 10к потоков. Какой быстрее посчитает и сколько ресурсов съест. Всякие -O2 и -O3 оптимизации для кода на плюсах использовать будет не спортивно, для схожести машинного кода.

Ну это просто смешно. Неужели вы реально думаете, что такая попытка чего-то стоит?

Если вы на 4х ядрах

Во-первых враньё номер раз. Ни на каких ядрах и ничего я не запускал. Я в мейн-потоке запустил 100500горутин, а далее в мейнпотоке был цикл, который никак не мог заблокировать остальные потоки.

без вытесняющей многозадачности

Приплыли. Ведь отсутствие вытесняющей многозадачности это и есть дыра в дизайне любых гринтредов.
запустите 4 cpu-bound потока

Очередной враньё. Никакие потоки запущены не были. Никакие cpu-bound-задачи на них не запускались. Запускался слип.

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

а потом захотите запустить 5ый, но он не будет выполняться, — это тоже дыра в дизайне?

Опять враньё. В го потоки(реальные потоки) вытесняемые. Иначе быть не может. Если же это не так — никаких 4-х процессоров нет и вся попытка изначально подлог, а однопоточный дизайн — дыра в дизайне.

Больше похоже на неправильное использование.

Ещё раз. Никаких вменяемых оснований для называния моего кода неправильным нет. Блокировка мейн-потока никак не может влиять на другие потоки, либо запущенные горутины, либо из шедулер. По определению.

Тем более всё это изначальный подлог, ибо создание горутины находится выше и шедулер 100% запустился.

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

P.S. Если так хочется посравнивать, можете сделать просто два распараллеленных cpu-bound теста рассчетов на хотя бы 10к горутин и 10к потоков.

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

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

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

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

Делается же это не так. Берётся 100% масштабируемая задача время выполнения 10к запусков которой поделенное на n реальных ядер(либо лучше посчитать сразу в n-топоках по 10к/n запусков)учитывается как эталон. Далее всё это запускается на 10к тредах и высчитывается оверхед.

По поводу го. Если с сями/крестами я уверен в том, что эталонное время будет состоять на >99% из времени исполнения того куска кода, что написал я. То в го это может быть не так. Он может 50% времени долбить свой шедуллер/рантайм, либо ещё какую херню и результирующих цифрах мы полечим 50% мусора. Но это ладно.

Всякие -O2 и -O3 оптимизации

Кресты без оптимизаций не имеют смысла к существованию. При этом надо понимать, что -O0 — это не отсутствие оптимизаций, а наличии пессимизаций из-за волатайла.

Но это ладно — я сделаю честно.
Вообще про «не включать `-ON` — самый смешной пассаж. Почему вдруг при соревновании в беге двух сущностей я должен своей отрубить ногу?
Не, ну это имеет смысл. Автор пытается исключить возможный выигрыш С++ за счёт более оптимальной реализации задачи, которая собственно и будет запускаться на 10к тредах. И в конечном итоге получится так, что С++ быстрее/такой же, но на самом деле его полезная нагрузка просто жрёт в n-раз меньше цпу, что собственно и нивелирует больший оверхед самих потоков в сравнении с горутинами.

Для того, чтобы это избежать — надо сравнивать реализации не друг с другом, а с деградацией в сравнении с запуском 10к раз на одном(ncpu) тредах.
А, точно, да, спасибо.

Поверхностно прочитал.

Может я просто не так писал слипы в го?

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


Вообще, вы по сути проверили скорость создания потоков. Создание потоков в Linux это быстрая штука, спору нет. Но вы же сами написали, что при равном количестве потоков/процедур у вас пример на C++ вылетает с нехваткой ресурсов. Потоки куда тяжеловеснее по стеку (по умолчанию, если память не изменяет, там два мегабайта), у горутин — два килобайта. Вставьте задержку и посмотрите на maximum resident size, я думаю, что код на C++ покажет гораздо больший расход памяти.

то этот цикл просто не отдаст управление гопроцедурам.

Ну дак цикл там один, а вёдер у меня 8. И судя по тому, что я нагуглил — го не однопоточный, а может раскидывать всё это на несколько тредов, либо этого он не может?

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

А что ему мешается запустить в параллельном треде? Тем более он запустился — он же вызвал горутину в которой есть слип. В чём проблема?
В вашем примере проще всего вставить очень маленький Sleep() в цикл проверки переменной.

Этот цикл — эмуляция нагруженного реального потока. Собственно это ещё одно причина из-за которой «горутины должны быть маленькие», хотя ничего не мешает расставлять какие-нибудь стоп-поинты(аля pthread_testcancel()).

Вообще, вы по сути проверили скорость создания потоков.

Ну да, ведь горутины именно про это.

Создание потоков в Linux это быстрая штука, спору нет.

Судя по бложикам го, судя по хайпу вокруг горутин — все меня(и не только меня) убеждают в том, что ОС не может даже в 100тредов.

Но вы же сами написали, что при равном количестве потоков/процедур у вас пример на C++ вылетает с нехваткой ресурсов.

Нет. Я писал не так — я писал, что активных потоков может быть 30к из-за каких-то ограничений линукса. А так же я написал, что я не знаю таких юзкейсов где надо иметь больше 30к АКТИВНЫХ потока.

Потоки куда тяжеловеснее по стеку (по умолчанию, если память не изменяет, там два мегабайта)

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

Это тратит только адресспейс, которого:
address sizes: 39 bits physical, 48 bits virtual

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

Поменять же размер стека никаких проблем не состовляет:

  pthread_attr_t attr_d, * attr = & attr_d;
  pthread_attr_init(attr);
  pthread_getattr_default_np(attr);
  pthread_attr_setstacksize(attr, PTHREAD_STACK_MIN);
  pthread_setattr_default_np(attr);
  pthread_attr_destroy(attr);


у горутин — два килобайта.

Ну обычно у стека есть защита — последняя страница ставить с prot_none и при при заходе на неё падает с «сегфолтом».

Если у го её нет, то значит любая горутина может спокойно покараптить стек другой горутины, а если она есть — стек уже не 2кб, а 8кб минимум.

>>Вставьте задержку и посмотрите на maximum resident size, я думаю, что код на C++ покажет гораздо больший расход памяти.
Не покажет. Я уже объяснил причины. По поводу памяти — при любом стеке птреды будут занимать 8кб на один тред(страница активный + страница для защиты). Если в го — это 2кб, то будет занимать в 4раза меньше.

Опять же — ничего не мешает запилить аналог птреда и с 2кб стека, правда всех мало волнуют эти 100мегабайт на 100к тредов.

И опять же, как я говорил — гц в реальном приложении на го сожрёт куда больше.
любая горутина может спокойно покараптить стек другой горутины

Через unsafe можно, если почти специально. На то он и unsafe. В обычной жизни нет (не рассматриваем ситуацию сейчас с багом самого го рантайма).
Как это реализуется? Это только подсчёт длинны стека, но опять же — это значит, что не вызовешь никакой сишный код. При этом это оверхд не слабый. Это можно реализовать как-то ещё?

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

Реализуется проверкой в прологах функций (оверхед там небольшой).

Ну хотя да, если там нету vla и прочих историй, то длину стека функции может почитать компилятор.

Вызов сишного кода выполняется с переключением на стек нативного потока, так что стек горутины не используется.

Но ведь суть всей ассинхронки именно во внешних операциях. Прочитать сеть, записать на диск, вызвать бдешку и прочее, а всё это си. Каким образом это работает?

(Простите, что не с свой разговор влез.)

Это общий разговор.

Каким образом это работает?

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

Мы говорим о вызове функций из нативных библиотек, или уже об асинхронном вводе/выводе?

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

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

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


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

Весь никакая ассинхронность не нужны, если операции не wait. А такие операции только системные, либо внешние, но опять же — через всё это системное ipc, либо сеть, либо файлы.

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

В Go очень много обёрток и собственных реализаций, в том числе для того, чтобы отвязать горутины от блокирующих системных вызовов. И отсюда же очень малое количество зависимостей у бинарников.


Весь никакая ассинхронность не нужны, если операции не wait. А такие операции только системные...

Я опять обращусь к примеру. (Сразу скажу, конкретной реализации именно этой части в Go не знаю, так что пример умозрительный, но кажется, что так и реализовано.) У вас есть несколько горутин, ожидающих ввода/вывода на сокетах. Вы можете сделать несколько потоков и каждый будет ждать ввода вывода, каждый будет иметь горутину в контексте исполнения. Но вы можете сделать иначе — вы можете использовать событийную модель. Горутина может вызвать собственную сетевую библиотеку, а та, обёртывая системные вызовы, добавляет сокет в список ожидания epoll(). При этом заблокируется только один поток на все сокеты. Как только epoll() просигналит, что на каком-то сокете доступен результат ввода-вывода, то это событие поступит в очередь событий, а планировщик даст зелёный свет на выполнение той горутине, которая ждала этой операции. Ради таких вещей горутины и задумывались.

Ну так Go и не использует libc (или что там идет заменой на других платформах, типа той же винды). Прямые сисколы, а вызов именно сишного кода только для явного вызова сишного кода, а не i/o и прочего.
… может раскидывать всё это на несколько тредов, либо этого он не может?

Горутины, конечно, разбрасывает. Но вы не дали планировщику их разбросать. Дело не в том, чтобы запустить горутину, которая спит, дело в том, чтобы выбрать сигнал на её пробуждение в цикле событий, который там под капотом.


Этот цикл — эмуляция нагруженного реального потока.

Горутины — не потоки.


Ну да, ведь горутины именно про это.

Нет, они не про это.


… все меня(и не только меня) убеждают в том, что ОС не может даже в 100тредов.

Ну, как видите, 100500 потоков не может, а 100500 (и гораздо больше) горутин может. Но это сравнение тёплого с мягким, это довольно разные вещи. Это распространённое заблуждение, думать о горутинах как о потоках.


… горутина может спокойно покараптить стек другой горутины, а если она есть — стек уже не 2кб, а 8кб минимум.

Го вставляет проверки доступного размера стека в прологи генерируемых функций, если стека не хватает на нужды функции, то он растёт. Поэтому guard page нет, и это вполне безопасно.


Не покажет.
Если в го — это 2кб, то будет занимать в 4раза меньше.

Ну вот видите, покажет. Тоже вполне себе разница. В реальности будет больше (я не поленился — шесть раз). Плюс маленькие приятности вроде переключения контекста из юзерспейса и обратно.


Но и это действительно не так уж важно, никого и впрямь не волнует расход памяти на потоки при таком чудовищном их количестве — просто потому что в таком количестве их никто не использует. Почему важно то, что горутины весят меньше, и почему их, бывает, запускают в таких количествах? Потому что горутины — это не потоки. Они используются не для распараллеливания вычислений и тому подобного. (Нет, используются, конечно, они всё-таки бегут поверх пула потоков, но это второстепенно.) Настоящая raison d'être горутин и каналов в го — это асинхронное выполнение. Это не совсем аналог потоков в других языках, это скорее аналог futures, promises, async/await, libevent и подобных вещей. Поэтому споры «горутины vs. системные треды» — довольно бесполезное времяпрепровождение. :)

Горутины, конечно, разбрасывает. Но вы не дали планировщику их разбросать. Дело не в том, чтобы запустить горутину, которая спит, дело в том, чтобы выбрать сигнал на её пробуждение в цикле событий, который там под капотом.

Не понят причём тут горутина, причём тут цикл событий? Ничего ему не мешает «их разбросать».

Горутины — не потоки.

Горутины тут не причём. Я вызвал цикл в основном потоке и всё втало раком. Потоки ли горутины, либо нет — никому не интересно и это ничего не меняет.
Нет, они не про это.

Именно про это. Если не про это — я слушаю ваши предположения.
Ну, как видите, 100500 потоков не может, а 100500 (и гораздо больше) горутин может.

Это не имеет смысла. Оно может во столько, сколько использовать имеет смысл. Работает не медленнее, при этом имеет преимущества системных потоков.

Может 100500 активных потоков, но 100500 активных потоков в го быть не может — может быть только(один? 4? 8?). 100500 потоков в слипе никому не нужно, ибо во-первых они будятся через адские кастыли, а во-вторых — стоимость их пробуждения будет нивелировать их смысл.

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

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

>>Го вставляет проверки доступного размера стека в прологи генерируемых функций, если стека не хватает на нужды функции, то он растёт. Поэтому guard page нет, и это вполне безопасно.
Это дороже. Опять же — как вызывать нативные(сишные) функции?

>>Ну вот видите, покажет. Тоже вполне себе разница.
Разница в чистых цифрах никакая тем более в сравнении с го в котором есть гц.

>>В реальности будет больше
Не будет. Будет именно так, как посчитал я. Не согласны — предъявите основание вашего утверждения.

я не поленился — шесть раз
Я померил — го 70мегабайт, а птреды 260. Запускалось это на 30к тредах, ибо линукс в больше не может. Как я сказал — тред 8кило * 30к, что ~235 мегабайт, что соответствует реальности. 30к * 2к — это ~59мегабайт, что соответствует наблюдаемым.

Почему важно то, что горутины весят меньше

Как мы уже выяснили — их «меньше» не преимущество, ибо в чистых цифрах оно ничтожно.

, и почему их, бывает, запускают в таких количествах?

Зачем?

>>Потому что горутины — это не потоки.
Это потоки. Им можно какие угодно вешать шильдики, но это потоки.

Они используются не для распараллеливания вычислений и тому подобного.

Поток не про распараллеливание — поток про «поток» — т.е. про параллельное исполнение множества потоков управления.

(Нет, используются, конечно, они всё-таки бегут поверх пула потоков, но это второстепенно.)

Как и обычные потоки.

Настоящая raison d'être горутин и каналов в го — это асинхронное выполнение.

Насколько я знаю — это именно треды.

Т.е. если я создам цепочку горутина->канал->горутина и т.д. — это будет не один поток, а 2.

Это не совсем аналог потоков в других языках, это скорее аналог futures, promises, async/await, libevent и подобных вещей.

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

Запускать это в горутинах, либо в потоках — разницы нет. Вернее как го-пацаны говорят, что есть, ибо горутины быстрее потоки, но это не совсем так, вернее совсем не так.

Поэтому споры «горутины vs. системные треды» — довольно бесполезное времяпрепровождение. :)

Да нет, это просто отмазки для избежания неудобной ситуации перед простым фактом — горутины не быстрее.

То, что в го есть какая-то логика поверх потоков — из этого ничего не следует. Прикрутить её можно куда угодно.

Были бы это не потоки, если бы все эти цепочки горутина->канал->горутина объединялись бы в цепочку калбеков в рамках одного потока.
… причём тут цикл событий? Ничего ему не мешает «их разбросать».

Я думаю, что тут будет удобнее на примере. В вашем коде, сразу после создания потоков, но до начала цикла поллинга вашего атомика (не внутри цикла, а до него), поместите один вызов runtime.Gosched() — сделайте одно переключение в контекст планировщика. После этого цикл может работать без пауз, но горутины уже завершатся нормально.


Именно про это. Если не про это — я слушаю ваши предположения.

Мне кажется, я уже рассказал, про что. Горутины — не для того же, для чего используются потоки. Там, где в го используются горутины, в C вы обычно используете libevent а не потоки. Да, их можно использовать для распараллеливания работы (если GOMAXPROCS не единица), но концептуально это инструмент для написания асинхронного кода.


Это не имеет смысла. Оно может во столько, сколько использовать имеет смысл.

Хорошо. Сделайте на вашей машине миллион. Не теоретически, а экспериментально.


Может 100500 активных потоков, но 100500 активных потоков в го быть не может — может быть только(один? 4? 8?). 100500 потоков в слипе никому не нужно...

А зачем вам активных 100500? У вас есть восемь ядер, поэтому всё, что вы создаёте сверху — явно не для того, чтобы держать их всех активными. Здесь мы возвращаемся к тому, что уже обсуждали — если вы создали 100500 потоков или горутин, то это не ради распараллеливания работы, это для асинхронной модели выполнения. Для этого и сделаны горутины.


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

Миллион одновременных клиентских соединений? Это чуть ли не канонический use case. Живут, что-то считают, засыпают на ввод-вывод, снова просыпаются, умирают.


Это дороже. Опять же — как вызывать нативные(сишные) функции?

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


Не согласны — предъявите основание вашего утверждения. <...> Я померил — го 70мегабайт, а птреды 260.

Двадцать восемь против ста шестидесяти семи на десяти тысячах. Можете мне рассказать, почему, если не лень. Но это не принципиально.


Зачем?

Для асинхронного выполнения кода.


Это потоки. Им можно какие угодно вешать шильдики, но это потоки.

Нет.


Поток не про распараллеливание — поток про «поток» — т.е. про параллельное исполнение множества потоков управления.

Поток не про распараллеливание, а про параллельное выполнение потоков? Это тавталогия какая-то, извините. В чём различие?


Насколько я знаю — это именно треды. Т.е. если я создам цепочку горутина->канал->горутина и т.д. — это будет не один поток, а 2.

Нет. Если вы установите GOMAXPROCS=1, то вы вполне себе получите один-единственный поток, но горутин будет две. При этом они будут крутиться в очереди выполнения в контексте этого потока. Это крупное различие.


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

Нет. Async/await и иже с ними не обязательно вызывают создание новых потоков. Фактически под капотом событийная модель — мы можем отметить, что этот кусок кода ожидает события, и как только в очереди событий оно появится, то этому куску даётся зелёный свет на выполнение; это вполне может выполняться в контексте одного потока.


Были бы это не потоки, если бы все эти цепочки горутина->канал->горутина объединялись бы в цепочку калбеков в рамках одного потока.

В чём-то так и есть — это похоже на цикл событий и этакий сахар над колбеками. Для этого не нужны потоки.


Вы как-то всё агрессивнее и агрессивнее становитесь. Я создал у вас впечатление пытающегося сказать, что ваш C++ — убожестно, и Go forever? Это ошибочное впечатление. Я просто пытаюсь объяснить, как всё это работает. Если я вас раздражаю, вы скажите, и я перестану.

В целом вся концепция "легких" потоков о том, что бы запускать кучу псевднопотоков в одном реальном.

Не верно. Тредпул, если это именно тредпулл с постоянно живущими потами — существует не для это. Он существует для нивелирования оверхеда на запуск потока.

Простите, но писать однозначно «не для. а для...» в данном случае некорректно. Число потоков вполне может быть ограничено ОС (физически ограничено, не настройками). В этом случае пул потоков и соответствующая модель будут использоваться как единственно возможное решение, а не только для ликвидации оверхеда.
Вот только сегодня как раз вышла прекрасная заметка Адама Левенталя; положу тут, за компанию: http://dtrace.org/blogs/ahl/2016/08/02/i-love-go-i-hate-go/
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории