Pull to refresh

Comments 112

По-другому называется раскрутка компилятора. Интересная тема. Например PyPy написан на PyPy, подробнее тут. Если кто-то из хабравчан может более подробно описать пошагово для несведущих в виде статьи — было бы здорово!
Раскрутка, если мне не изменяет память, это несколько другое.
Сначала на каком-то существующем языке пишется полное по-Тьюрингу подмножество языка (к примеру, один условный оператор и один цикл), после этого на уже новом языке переписывают этот компилятор и продолжают разработку нового языка на новом языке. Такой подход ускоряет разработку, если новый язык, в сравнении со старым, к этому способствует. Так был написан Pascal, к примеру.
Тут же всё несколько иначе — версия языка уже перемахнула за 1.0, а он всё ещё содержал «чужой» код. Это именно переписывание.
Я правильно понимаю что теперь go не собрать без бинарного компилятора go? Если так, не вижу с чем тут можно поздравлять.
А в чем проблема? Вы боитесь, что все компиляторы Go исчезнут?
GCC вон тоже без GCC не соберется.
Проблема в том что это неудобно и небезопасно. Одному компилятору в системе (компилятору C/C++) это можно простить — он основа всего. Но он также поддерживает кросс-компиляцию и для него есть альтернативы (gcc/clang) которые могут пересобирать друг друга, поэтому возможность поиметь в компиляторе закладку, которая вставляет себя в свежесобранный компилятор уменьшается. К go ничего из этого не относится. Хотя-бы 3-stage bootstrap он делает?
Также не совсем понятно как портировать его на новые системы.
Есть же gccgo который писан на С++ и погружен в инфраструктуру gcc. Так что для Go есть как минимум два компилятора.
Если он способен собрать go, то наверное да, его можно использовать для bootstrap'а и проблему это частично решает.
Вы боитесь, что все компиляторы Go исчезнут?

Вполне может быть. Или как минимум будут заброшены и рано или поздно не смогут собрать Go компилятор написанный на Go.
Старый код из репозитория никуда не денется. Можно будет сделать чекаут сишной версии.
Это очень сильно усложняет процесс портирования на новую систему. Вот, у Вас есть новая ОС. Под неё портировали GCC. Как получить на ней GO?
элементарно — gccgo это часть gcc, следовательно если под эту ОС есть gcc, значит и компилятор Go там уже есть автоматом :-D
если не будет ассемблерных вставок и специфичных под ось сишников. Это придется переписать. Порт gcc — означает, только то, что он может собрать образ С и С++ компилятора, когда то в gcc входили Ада, D & Objective-C компиляторы, Аду выпилили, теперь «независимый» проект, Objective-C — забросили, теперь в LLVM, D — не помню, перешел на D2? Есть ли шанс, что в такой же ситуации не выпилят go?
Когда изменился статус GNAT в GCC? По моему он как входил в GCC так и входит (естественно его пилит в основном AdaCore).
AdaCore — все время фротэнд и пилила, только за бекендом не успевает, полностью забрала с gcc 4.0

## You may point your browser to the AdaCore download page, choose your platform and 2014, then select the file to download.
Насколько я понимаю, они вполне себе продолжают взаимодействовать с FSF, по крайней мере сборка GNAT не от AdaCore, а от FSF все еще имеется (в том числе в том же mingw 4.7 и прочем) — сборка GNAT от FSF отличается прежде всего лицензией (ну и стыковкой фронтенда и бекенда — этим там занимаются несколько другие люди).

То есть GNAT никуда из gcc не выкинули. См. например чейнджлог для gcc 4.9: gcc.gnu.org/gcc-4.9/changes.html — там есть секция Ada. Так что все нормально, gnat как был частью gcc так и остался. Хотя конечно модель разработки GNAT отличается от модели разработки например g++.
— сборка GNAT от FSF отличается прежде всего лицензией (ну и стыковкой фронтенда и бекенда — этим там занимаются несколько другие люди)
AdaCore — выпускает аду под двумя лицензиями: GNU и коммерческой, отличие в утилитах, gnat — весь GNU, все исходники есть. FSF к аде никакого отношения не имеет. AdaCore берет gcc бекэнд, что GNU лицензия позволяет, а так все в порядке.

Был момент, ада долго не обновлялась, мы боялись, что AdaCore закроет разработку и обанкротят, Есть такие же точно опасения и по поводу go, если google прекратит разработку. под х86-64 может комьюнити и потянет, про остальные архитектуры… тем более, что на go, качество кода будет как у gcc на PowerPC :(
Разработчики Go собираются предоставить скрипт, который автоматически соберёт Go 1.4 из старых сишных исходников, потом Go 1.4 соберёт Go 1.5, Go 1.5 соберёт Go 1.6 и т. д.
Позже они намереваются генерировать исходники компилятора на Си, необязательно быстрого, но корректного.
Здесь можно почитать подробнее.
Ну, если они будут поддерживать в работоспособном состоянии тулчейн, который сможет это всё собрать с ноля, то да. В конце-концов, GCC уже некоторое время можно собрать только так — собрав сначала более старый GCC.
Ну как бы есть с чем поздравить, теперь его будет легко развивать тем, кому он действительно нужен, в смысле разработчикам на Go.
который так или иначе возникает во всех языковых коммьюнити, и успеха в котором практически никто не добивался

Scala собирается ею же, упомянутый выше PyPy, Rust, FreePascal, CoffeeScript и TypeScript… Складывается ощущение, что это не такая уж редкость.
Более того, self-hosting compilers считается стандартом к которому стремятся все «нескриптовые» языки. Откуда автор взял «и успеха в котором практически никто не добивался» вообще не представляю.
Окей, каюсь — статистику я не делал, но именно такое ощущение у меня сложилось за некоторое время чтения комментариев на тему бустраппинга в других языках — о том, что да, пробовали и делали многие, но не у всех получалось, а у кого получалось, реализация оставалась в стороне под отдельным именем (как FreePascal или PyPy).
Обновлю, пожалуй, текст ремаркой.
Согласен. Очень удивила эта фраза.
Crystal стоит в копилку добавить. Но для того чтобы собрать проект необходими скачивать прекомпилированый бинарник самого же кристала. Бутстрап на новой платформе я полагаю нетривиальный.
Да да, делфи тоже собирался собой
Понимаю, что рано ещё говорить о тестах, но есть какие-то метрики, в сравнении с Сишной реализацией?
реализовать её на C не представлялось возможным. На Go его реализовать будет намного проще
Вот это поясните, пожалуйста. Как это — не возможно реализовать на С, а на другом ЯП — возможно.
Думаю, что только «деды» в тим помнят «с», остальные только «go» (вше рады, фто все на одном яжыке! младшая группа яслей «Ромашка»)
«Не представлялось возможным» это скорее «в адекватные сроки и так, чтобы потом не было больно смотреть и развивать написанный код». Код для работы с concurrency алгоритмами на Go в разы проще, соответственно и затраты на написание намного меньше, при более понятном и читабельном коде.

Чтобы проще было понять — замените в том предложении С на asm (немеренно утрирую). Конечно, можно написать всё на ассемблере, но сложность кода, возможность его оптимизировать/рефакторить/etc и время его написания — на порядки выше.
Аналогично и с C vs Go.
Понятно. Я думал, что такие низкоуровневые критичные к производительности штуки только на С и пишутся.
Вставки на C и asm вероятнее всего никуда не денутся, просто будут на своём месте: реализовывать редкие очень критичные к производительности вещи, которые на Go недостаточно эффективны.
А как вставки и рантайм связаны с языком на котором написан компилятор?
Напрямую — не связано. Месседж в том, что в компиляторе, вероятно, останутся вставки C-кода для производительности. В остальном же писать и поддерживать хоть сколько-то сложную логику на Go несравнимо проще и приятнее.
«Go» столь же простой, сколь просто «Go» подмножество «C», есть море различных диалектов призванных сгладить дефекты «С»( en.wikipedia.org/wiki/XC_%28programming_language%29 en.wikipedia.org/wiki/List_of_concurrent_and_parallel_programming_languages www.cilkplus.org/ или run-time www.cs.kent.ac.uk/projects/ofa/jcsp/ ), eще раз (по поводу hard real-time)
### реализовать её на C не представлялось возможным. На Go его реализовать будет намного проще
первая часть — бред, run-time «Go» был уже на «С»,
вторая — странная: есть целые RTOS на «С» куда более real-time, чем самописное универсальноe на Go! Если хотите hard real-time, язык написания не имеет значения, главное, чтобы OS держала RT(hard), и хороший конвертер в «С», чтобы вызывать заоптимизированные примитивы и планировщики.
Так, все же, каковы истинные мотивы перехода на Go?
Смотрите, я в процессе разработки Go не участвую, поэтому в этом споре(?) с одной стороны есть вы, утверждающие, что язык написания не имеет значения, и есть авторы Go, которые, собственно, своими ручками это все пишут, и утверждают, что для них язык имеет критическое значение, чтобы идти дальше. Угадайте, чья сторона аргументации мне кажется более правильной?
я не спорю с утверждением, что «для них язык имеет критическое значение», я хочу знать — почему это так, я уже привел пример, что языковой повод притянут за уши, и первый мой комент — повод в том, что комьюнити разучилось программировать. Угадайте, что я думаю о вашем вопросе?
Кстати, сборщик мусора это ж не часть компилятора, а часть рантайма языка (да, для некоторых типов сборщика мусора нужна некая минимальная поддержка со стороны компилятора, но это мелочи). Соответственно каким боком реализация GC и рантайма имеет отношение к тому на каком языке компилятор писан?

И правильно ли я понимаю, что теперь и рантайм Go будет полностью на самом Go, что приведет к еще бОльшей просадки производительности приложений относительно приложений на Си?

PS. Посмотрел в changelog — бОльшую часть рантайма на Go переписали уже в 1.4:
As mentioned above, much of the runtime was translated to Go from C, which led to some reduction in heap sizes. It also improved performance slightly because the Go compiler is better at optimization, due to things like inlining, than the C compiler used to build the runtime.

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

В общем вывод — если хочется скорости, то gccgo наше всё!
Да, рантайм был переписан в 1.4. Насчет вопроса «каким боком компилятор» — не буду врать, подробностей не знаю, но это то, что звучало в ответах на вопрос о concurrent garbage collector в мейллистах.
Компилятор должен генерировать код и данные в расчёте на сборщик мусора (если это не универсальный консервативный сборщик со всеми своими недостатками).
Ну, о чем я собственно и написал (например тот же llvm это умеет, но это не значит что llvm тебе дает даром GC — нет там GC, GC надо писать отдельно). Но это все сильно проще чем собственно сам GC.

И, насколько я помню, у Go был (в версии 1.0 что ли) как раз консервативный сборщик мусора. Сейчас сборщик уже другой.
Да, шаблонов/генериков реально не хватает. Это, пожалуй, самое слабое место языка.
О, а расскажите о реальных задачах, в которых вам реально не хватает генериков?

Я в курсе основных use-cases, но на практике, из того, что нельзя красиво решить в Go — мне ни разу не приходилось делать. Поэтому вот интересны практические задачи из реальных проектов, для которых необходимы шаблоны или подобные реализации.
Ну, прежде всего конечно же не хватает возможности использовать (и создавать!) нормальные типизированные контейнеры. То есть без этого настолько неудобно, что просто ой. Кроме того, довольно глупо тратить время во время работы приложения на проверку типов элементов в контейнере, если мы на этапе компиляции и так знаем что там все будет однотипно. То есть тут шаблоны бы еще и ускорили работу приложения.

А еще, если бы в Go была бы не только RTTI, но и CTTI… То всякие сериализации работали бы просто на порядок быстрее… Эх, мечты, мечты… :-)
Окей, типизированные контейнеры — это понятно. Хотя, помимо соображений скорости, я не сильно вижу, чем решение с реализацией интерфейсов (как в btree, к примеру) явно лучше шаблонов. Ну и про возможности go generate, полагаю, вы в курсе.

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

Просто давайте откровенно — реализация generics — это всегда slowdown либо компилятора, либо рантайма, не говоря уже об усложнении системы типов и кучи сопутствующих побочных эффектов. Как бы вы не реализовали генерики, это сразу же порождает 100500+ результатов в гугле по запросу "%LANG% generics sucks". И, как всегда в дизайне языков, тут вопрос компромисса — если 90% программистов ежедневно пишут свои контейнеры — то, безусловно, какая-никакая но реализация generics в Go уже была бы. Но поинт в том, что огромное количество людей (и не только авторы Go) считают, что generics алгоритмы и типы — несколько переоценены, и те use-case для generics в Go на 90% решаются идиоматически (даже если вы об этом не знаете еще)

Ну и да — из личного опыта — мне не приходилось упираться в «отсутствие generics». Вообще. Никогда. Объясните, что я делаю не так? Какой тип софта я должен начать писать, чтобы упереться в это? Без сарказма вопрос.
Сколько в вашей программе упоминаний interface{}? Вместо каждого из них можно использовать generics.
Нет, это не тот ответ. Обратный ответ («Сколько в вашей программе generic-типов? Вместо каждого из них можно использовать interface{}») точно такую же пользу несет.

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

Практически любое использование interface{} — это ужасно, некрасиво и костыль (исключение — это коллекции разнородных данных, у которых нет никакого общего интерфейса). Никто вам не мешает заменить все генерики в Java на Object и касты. Результатом будет ухудшение читаемости программы.
Ну оно так и было :-) До версии 1.5 (ака J2SE 5.0).

Причем это было не так и давно — 2004 год. Напомню что java вышла в 1995 году. То есть 9 лет язык был без дженериков или чего-то подобного. 9 лет так вот страдали с Object'ами в коллекциях.

Сторонняя реализация java с дженериками (называлась Generic Java) была создана в 1998 году. Подробней об этом здесь: en.wikipedia.org/wiki/Generics_in_Java
В простом случае, generic'и полезны для обёрток вокруг map (например, множество на основе map[<type>]struct{}). Можно обойтись копипастой, но это некрасиво. Их отсутствие обходится, где-то embedding'ом, где-то interface{} контейнерами, где-то генерацией кода, но генерики для проектирования (но не для дебага) гораздо проще.
И всё же — «их отсутствие обходится» — это заведомо предвзятая фраза.

Чуть ниже запостили ссылку на отличный сводный док по тому, какие есть реальные применения generics и как эти же задачи решаются в Go без generics (и это не тоже самое, что «обходится») — рекомендую почитать всем в этой ветке.

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


Ну вот и я не вижу чем решение с реализацией интерфейсов явно лучше шаблонов :-) Будем считать что у нас тут консенсус, и решение с шаблонами будет полюбому лучше :-)

Просто давайте откровенно — реализация generics — это всегда slowdown либо компилятора, либо рантайма


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

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


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

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

Дженерики и шаблоны — это статическая типизация, interface{} — динамическая. Вот и все. Если активно используется interface{} и нет от этого никакого дискомфорта, то данный проект с тем же успехом данный программист может писать и на питоне (но, видимо, не на js — в Go таки даже для interface{} типизация строгая (равно как и в питоне), а на js — слабая).

В Go имеем некое половинчатое решение, для встроенных типов (типа того же map) имеем статическую типизацию, а для рукописных типов контейнеров (типа того же btree) — только динамическую. Что вызывает некий когнетивный диссонанс при использовании и не добавляет концептуальной целостности языку. В общем, как в том анекдоте «вы или крестик снимите, или трусы наденьте».

Если бы я хотел писать данный проект на динамически типизированном языке, я бы взял python. А Go был выбран, кроме всего прочего, в том числе из за статической типизации (и дело тут не в скорости исполнения приложения).

PS. На самом деле Go это как минимум третий язык который на стадии своего развития проходит через фазу «работаем пока без шаблонов/дженериков» — вначале в java не было дженериков, затем в C#, но все современные статически типизированные языки общего назначения так или иначе дженериками все же обзаводятся (в том или ином виде — у java и C# они сильно разные).

PPS. Если не секрет, а на чем вы писали до Go? Какими еще языками пользуетесь?
На самом деле Go это как минимум третий язык который на стадии своего развития проходит через фазу «работаем пока без шаблонов/дженериков»

Причём некоторые параметризованные типы в них всё-таки приходится встраивать (в Go — массивы, каналы, что-то ещё?), а вот пользовательские делать запрещают =\
map еще. Массивы то ладно, а вот map (на самом деле это аналог unordered_map) штука не тривиальная и её тем не менее пришлось зашить прямо в язык. При этом если нужен аналог обычного С++ map, то нужно уже лепить руками контейнер с динамической типизацией (interface{}), что весьма неудобно.
Я понимаю в каком случае применить Python, понимаю в каком случае применить Си(в том числе 99) и С++, но вот куда в это представление впихнуть Go я уже давно не знаю.
Так же пока не могу точно ответить на счёт Rust.
Ну, где использовать Rust и я не знаю (ибо он до сих пор не стабилен). А Go хорош тем, что у него отличная инфраструктура (система пакетов и так далее), искаропки он отлично работает с сетью в том числе с http и всякими вебсокетами, он легко интегрируется с Си (то есть он понимает сишные хедеры сам и не нужно биндинг писать совсем), у него хорошая скаробочная система сборки ну и он все же статически типизирован.

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

В результате это все пишется довольно легко и быстро (сетевое взаимодействие так вообще очень приятно писать), если что-то где-то шлепается, то шлепается с осмысленной диагностикой. Утечек памяти нет. Да, ну и до кучи в качестве бонуса имеем отличную кроссплатформенность — написанное работает и под линуксами, и под OS X и под виндой. Иногда бывает очень полезно иметь возможность развернуть систему на том что есть под рукой, локально. Да, и работает оно тоже весьма быстро и не тащит за собой какие-то там интерпретаторы да виртуальные машины.

Естественно если писать что-то большое (сотни тысяч строк кода) и требовательное к ресурсам, то, на мой взгляд, нужно брать какой-нибудь С++ (просто потому что на таких объемах работ мелкие геморрои вроде систем сборки, сборки сторонних либ руками под данный дистр и так далее уже не играют какой-то особой роли, а вот вопросы производительности (в том числе полный контроль за менеджментом памяти) и наличие тех же шаблонов — уже будут играть).
По вашей логике, тогда нету места Python и Ruby в написании сетевых сервисов?
ЗЫ я так и не нашёл корутины в Go для асинхронного программирования как в Tornado или AsyncIO. goroutine это хоть и похоже но всё же иное.
Это не моя логика, это моя практика :-)

Для асинхронщины в Go есть да, goroutine + каналы, больше ничего и не нужно (если вдруг чего-то не хватает — интересно было бы послушать чего именно). Это конечно не так здорово как потоки в erlang'e, но в принципе достаточно.

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

А так да, для нашего случая (для этой конкретной части проекта) наилучшим решением оказался Go.
goroutine это скорее ближе к лёгким thread. А я говорю вот про такое: tornado.readthedocs.org/en/latest/gen.html смотрите там где gen.coroutine.
Т.е. линейное написание асинхронного кода.
Дык в горутины как раз для этого и есть. Там точно также линейно все и пишется.
Дык горутины не возвращают значения. Если я не прав то ткните в документацию.
Я просто не понимаю как можно написать аналогичный код:

response = yield http_client.fetch("http://example.com")
do_something_with_response(response)


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

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

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

Нет в main они думаю не будут. Это всё работает в рамках event-loop.

чем это отличается от обычного синхронного тупого кода на си, где http_client_fetch будет обычным блокирующим вызовом?

Много чем, но для начала это не блокирующий вызов. :)
Как я уточнил выше, это явная асинхронная работа. http_client_fetch возвратит «future» и отдаст управление эвент лупу, когда запрос будет обработан и результат скачан то event-loop вернёт управление к вашей функции начиная с yield передав туда результат работы «http_client_fetch». Пока происходит скачка данных, event-loop обрабатывает другие запросы и активирует другие методы вашего веб сервера.
В Go каждый запрос к серверу был бы горутиной, а каждый sys-call планировщик замораживал бы его до результата.
Эмм… Нет :-) Работают же мои демоны одновременно обслуживая множество соединений (в одном потоке).

Можно более развернутый пример где была бы видна работа этого самого event-loop'a? То есть несколько разных запросов и проч. Я постараюсь аналог накидать на Go. (ну и словесное описание задачи тоже было бы хорошо увидеть)
Я выше давал ссылку. Там есть несколько примеров.
class GenAsyncHandler(RequestHandler):
    @gen.coroutine
    def get(self):
        http_client = AsyncHTTPClient()
        response = yield http_client.fetch("http://example.com")
        do_something_with_response(response)
        self.render("template.html")


Представьте, что вот сюда (в метод get) пришло сразу 10 клиентов(запросов), которые хотят получить свою порцию html.
Сразу как первый запрос дойдёт до yield http_client.fetch(«example.com»), начнёт обслуживаться следующий который опять дойдёт до этого места и event-loop займётся следующем и т.д. К примеру на 5 запросе уже придут данные для первого вызова http_client, и система для первого запроса пойдёт дальше, отработав шаблоны и вернув клиенту html. После этого сразу же будет отрабатываться следующая задача. Но при разработке это выглядит вполне себе линейно, при чём вы можете сами писать методы которые хотите запустить асинхронно.

Работают же мои демоны одновременно обслуживая множество соединений

Работают, по тому, что когда syscall закончен планировщик возбуждает нужную горутину. Но чуть что горутина начинает плодить совсем себе нативные threads — groups.google.com/forum/#!topic/golang-nuts/2IdA34yR8gQ. ^_^

Про сам планировщик тут: morsmachine.dk/go-scheduler
Плодить threads им запрещено, ибо явным образом выставлено GOMAXPROCS=1 :-)

Я правильно понимаю, что для моделирования ситуации достаточно написать http-сервер который всем клиентам сказавшим GET одновременно раздает ну скажем гигабайта по 4 респонза (ну или просто о-очень долго льет 10 кб данных каждому)?
Не только. Это редкий use-case кроме наверное длинных запросов. Чаще к примеру вы делаете сложный запрос к БД, который будет несколько секунд длится. Или к примеру (как у меня часто) обращаетесь к сторонним http API которые могут уже до пол минуты возвращать ответ. Эти долгие запросы не будут блокировать остальные запросы, и при этом не будут плодится ни процессы ни потоки (что сильно экономит RAM).

Я догадываюсь как это будет выглядеть (на каждый запрос делаем go get()). Просто в Go вы не сможете вручную контролировать когда отдать управление планировщику, а когда нет (некоторые запрос к redis/memcache тем более через unix сокеты лучше делать синхронно, для повышения производительности :) ).

К слову в тему www.reddit.com/r/golang/comments/1aajw0/just_landed_the_network_poller_epoll_etc_is_now.

Ну и прям почти про наш разговор: stackoverflow.com/questions/21102078/golang-methods-that-will-yield-goroutines
Ока-ай, изменяем задачу — значится мы теперь совсем не сервер, а очень даже клиент. Нам нужно сделать какой-нибудь http get к сильно тормозящему серверу, и пока оно тормозит и сосет оттуда данные медленно медленно, продолжать печатать в консольку раз в секунду что-нибудь. Так? ;-)

Да, при этом у нас процесс должен быть один и поток должен быть один.
Для браузера мы сервер но для сторонних API и БД мы клиенты.
искаропки он отлично работает с сетью в том числе с http и всякими вебсокетами, он легко интегрируется с Си (то есть он понимает сишные хедеры сам и не нужно биндинг писать совсем)

Этим может похвастаться большиниство новых (и не очень языков). Тот же Rust или совсем новичок Crystal (aka компилируемый Ruby с блекджеком). Например вот так вот выглядит вебсервер на Crystal:

require «http»

server = HTTP::Server.new(8000, HTTP::StaticFileHandler.new("."))
server.listen


В результате имеем бинарник размером в 90K и минимумом зависимостей. Скорость выполнения бенчмарков ~10-30% лучше чем у того же Go.
Ну, про Rust я уже написал — он сейчас находится не в том состоянии чтобы его где-то использовать.

Про Crystal первый раз слышу — что у него с пониманием сишных хедеров?

PS. У бинарника который получается у Go зависимостей нет вовсе. Он всебя статически влинковывает все что нужно и это довольно удобно.
Про Crystal первый раз слышу — что у него с пониманием сишных хедеров?


Работа с нативными библиотеками там одно удовольствие

Вот создание байндинга
https://github.com/manastech/crystal/blob/master/src/curses/lib_curses.cr

Вот его использование
https://github.com/manastech/crystal/blob/master/src/curses/curses.cr

Crystal очень интересный язык и понравится тем кто активно использует Ruby, но хочет производительности как в C.
Ну, то есть биндинг все равно писать надо, и хедеры сишные оно не понимает (поэтому и нужно руками писать lib_curses.cr), соответственно если в либе изменится сигнатура функций (аргументы например, но не имена) оно будет работать просто не так как надо (но при этом все соберется и слинкуется).

А вот Go понимает сишные хедеры и биндинг там в общем то можно и не писать. Если сигнатуры поменяются — то будет ошибка компиляции с явным тычком носа в те места где сигнатуры не совпадают.
В таком случае в Го проще будет.

То есть Го парсит *.h файл? А что если имя в хедере не соответсвует имени символа в библиотеке (например из-за использования аттрибута alias)?
Да, парсит. Это называется cgo ( golang.org/cmd/cgo/ ). Если не соответствует то будет ровно то же самое, что бывает в этом случае и в Си — ошибка компоновки.

У нас код тех самых демонов в основном написан на Го но там есть вкрапления на Си- оно все абсолютно бесшовно собирается целиком в единый исполняемый файл.

За это я лично Go и ценю (кроме всего прочего). Собственно даже яблочный Swift работает с Си намного более геморройным образом.
Если не секрет, а какие именно С-библиотеки используете? Что-то очень специфичное или просто выбрали С-реализацию, для большей скорости?
Свои. У нас реализация некоторой математики на Си писана. Там Си используется и потому что скорость и потому что эти алгоритмы нам нужны не только на сервере, а Си он везде применим, на всех платформах, в отличие от Go/Rust/ObjC/Java/etc.
Rust — Там где нужна скорость Си и безопасность памяти, как в языках со сборщиком мусора
Go — там, где нужно простая и легковесная ассинхронность
ну, Rust тоже как бы метит на легкую асинхронщину и даже на легкую многопоточность. При этом он вроде как будет даже более высокоуровневым нежели С++, не то что Go. Но у Rust беда одна — его нельзя использовать до сих пор :-) Собственно даже D использовать нужно с большой опаской и оглядкой. А вот Go вполне себе стабилен и при этом, по совокупности показателей, весьма удобен.
Rust не более высокоуровневый, чем С++ или С. И более низкоуровневый, чем Go.
Метит он скорее на безопасную многопоточность и асинхронность, чем на лёгкую. Arc<RWLock<i32>>(вот, кстати, и дженерики) просто для того, чтобы безопасно сделать целое число, которое можно читать/редактировать из разных потоков — не сказать, чтобы легко…
У Rust нет GC, нет «лёгких потоков»(вроде goroutine), нет динамической типизации.
Ожидаемая дата релиза версии 1.0: 15 мая
Ну, на самом деле Go более низкоуровневый чем C++ :-) Под высотой уровня я подразумеваю возможность создавать пользовательские абстракции, чем возможностей больше — тем уровень выше. У Go с этим явно хуже чем у C++. А у Rust с этим примерно также (где-то лучше где-то хуже) как и у C++.

GC сам по себе на «высоту уровня» не влияет.

А легкие потоки у Rust, как это и положено высокоуровневому языку, находятся в библиотеке: doc.rust-lang.org/0.11.0/green/ (это в низкоуровневых языках подобные вещи приходится вшивать в сам язык, ибо выразить такие абстракции этим языком не представляется возможным).
Ясно, я думал под «низкоуровневостью» вы имеете в виду «близость к железу».

Эта библиотека не работает, и без поддержки компилятора работать, по утверждениям разработчиков Кust, не будет, а таковая поддержка не планируется.
Не, близость к железу вторична (ну то есть хорошо когда она есть (c возможность от оного железа абстрагироваться), но и без нее жить можно во многих случаях).

Хм. Какой-то Rust не настоящий… Вон в том же хаскелле вроде как green threads и без особой поддержки компилятора сделали.

В общем, я укрепился во мнении что Rust до юзабельного состояния если когда-то и дойдет, то точно не в ближайшие год-два. Поэтому я пожалуй буду продолжать упорстовать во грехе и не буду его рассматривать как достойную альтернативу C++ или Go в своих проектах. :-)
На сколько я понимаю, в данный момент авторы преподносят Rust более безопасной альтернативой C и C++, в том числе для встраиваемых решений.
Они совсем в разных нишах с Go. На Rust сложнее писать(в основном из-за лайфтаймов и отсутствия сборки мусора), но он ближе к железу.
Ну, основная цель и основной, флагманский проект на Rust это все же не встраиваемые решения, а просто многопоточный движок браузера. Именно поэтому в Rust вкладывается Samsung и поэтому Rust вообще был придуман мозиллой.
Да. Это ниша Rust, и он не конкурирует с Go, так как у Go другая ниша.
Ну, ниша у Rust таким образом очень узкая — вот поднимите руку, кто тут движок браузера пишет? ;-)
Ниша Rust там, где вы бы не стали писать на Go, но выбрали бы C++/C. Браузер просто один из примеров.
Ну вот я знаю одно место где я бы точно-точно не стал бы использовать Go — при программировании микроконтроллера с 512 байтами ОЗУ на борту (есть у меня тут такой). Для этого я использовал С++ (c лямбдами да шаблонами, да).

Сюда Rust подошел бы? ;-)
Да, если есть соответствующий бэкэнд для LLVM.
В смысле? Rust точно-точно работает совсем без рантайма?
Да. Зависимость от рантайма была, но ее больше нет.
Если активно используется interface{} и нет от этого никакого дискомфорта

В том-то и дело, что interface{} не используется «активно». Даже проскакивает периодически в статьях для новичков — мол, interface{} в большинстве случаев вам не нужен, не лепите его где не нужно.
Я абсолютно согласен со всеми утверждениями про «в Go полу-статическая, полу-динамическая типизация» — но у меня нет в голове стереотипов, заставляющих записывать это сразу в минус. И против реализации generics темплейтами тоже ничего особо не имею (кроме того, что откуда-то берется стимул их использовать по любому случаю, и код становится почти не читабельным, и уж совсем не-дебагельным) — но я понимаю и разделяю позицию авторов Go.

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

Autoboxing/unboxing — это не оверхед?

PPS. Если не секрет, а на чем вы писали до Go? Какими еще языками пользуетесь?

Сначала на С, потом (и в основном) на С++, потом ушел на Python, который чуть упростил жизнь, но по понятным причинам это был несправедливый размен. А потом наткнулся на Go и буквально через пару вечеров смог писать production-level код. Так что для меня Go — это полноценная замена С++, которым я был недоволен по многим пунктам, но альтернативы которому особо не было.
Кстати, возможно мне так просто понимать позицию авторов Go по многим вопросам, потому что моя причина ухода от С++ совпала с причинами появления Go.
Некоторые любители динамических языков тоже заявляют, что не видят задач, где реально была бы нужна статическая проверка типов, что её польза переоценена, и что лично они в её отсутствие не упираются =)
При работе с Python ты и впрямь почти не упираешься в это. Но и там нету interface{}. Для C++ это более чем естественно и без типов было бы туго (область применения другая) (хотя и в C++ есть auto но это о другом).
Вероятно просто они не сталкиваются с такими задачами, так как работают в определенной области.
Возможно, так и есть. Но я уже не первый раз задаю этот вопрос — покажите примеры задач, где отсутствие generics — блокер, и ни одного адекватного ответа пока не было, к сожалению.
Не знаю, мне уже прямо неудобно. Вот такие комментарии с аналогиями «любителей динамических языков» писать легко, это понятно. Но до сих пор ни один человек в этой ветке не смог привести пример из реального проекта, где generics был бы стоппером, и не решался идиоматически Go.
Мне кажется это ведь просто — если программист и вправду жить не может без generics и считает, что это обязательный атрибут современного программирования — то должно быть легко вспомнить реальный случай и привести его в пример.

Просьбу эту заминусовали, вместо того, чтобы дать ответ по сути. Показательно, по-моему.
И это лишь подтверждает чисто теоретическую тему спора. На практике отсутствие generics в Go никак не мешает писать очень качественный код.
Писать качественный код и решать проблемы идеоматичным для данного ЯП способом можно и на фортране-77 (и такого кода написано МНОГО). Да и на коболе тоже в общем то можно. Вопрос лишь в том, сколько усилий придется для этого приложить.

Использовать interface{} мне приходится к сожалению часто (ибо вшитых в язык контейнеров не хватает, а любой библиотечный контейнер работает исключительно через interface{}), что ухудшает самодокументированность кода (вот тут объявлен список, какие элементы будут в него класть? а не ясно!) и увеличивает вероятность ошибки (периодически то тут то там все же сыпятся ошибки приведения типов из interface{}, в том числе в сторонних либах, увы).
Ну, лично я вас не минусовал. А аналогию с «динамистами» привёл, чтобы показать, что убедительный стоппер в принципе привести очень сложно – критерии очень нечёткие, и для любой полезной штуки найдётся армия людей, которые всю жизнь без неё задачки решали и им норм. На С вон качественный код и без генериков, и без ООП, и много ещё без чего пишут. Хотя и там генерик-макросы в новый стандарт впилили.
Так что я, конечно, попытаюсь найти вам пример, но сначала попрошу сообщить достаточное условие «упираемости», чтобы быть уверенным, что он вас устроит.
Да, про заминусованную просьбу показать пример — это не лично к вам, конечно же, было.

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

Я пишу, в основном, серверный/сетевой софт, иногда прикладное/gui/мобильное всякое — и основные используемые языки — C/C++/Python. Для меня проблема давным давно не в «сэкономить лишний такт процессора или лишний килобайт», а в том, чтобы быстро выдавать качественный и надежный продукт, который работает в современной софтверной экосистеме, с современными технологиями и протоколами. И C++ и Python обладают целым рядом недостатков, которые превращали ежедневную работу в унылую тоску, боль и борьбу с инструментарием, вместо написания кода. К С++ основная претензия — это излишняя сложность, которая только возрастает с годами. Чтобы написать простенькую по меркам 2015 года программу (скажем, простенький REST-backend) — нужно 5+ лет опыта C++, доскональное знание библиотек STL/Boost/ACE/TAO (а их именно нужно знать, с документацией и интуитивностью их API большие проблемы) и несколько томов литературы. Блин, да мне для создания переменной нужно думать, какой из десятка умных поинтеров буста выбрать! И это для простой программы, которая просто не будет падать. Тот фан, который некогда был от процесса написания кода, куда-то исчез.

И тут появляется Go — который был рожден как результат абсолютно таких же измышлений и недовольства существующим инструментарием, только от людей, в тысячи раз умнее меня, от людей с колоссальнейшим опытом в разработке ПО, и хорошим тылом в виде Гугла, позволившего им начать новый язык. Практически всё в Go мне понравилось сразу — и идеология KISS в фундаменте дизайна, и отталкивание от практического опыта, а не от теоретических выводов PLT, и очень низкий порог входа — вобщем, буквально за несколько часов я уже чувствовал, что язык знаком давным давно, а еще через пару вечером уже мог писать production-level код. И всё это с фантастическим тулингом, возможностями по профайлингу, оптимизации, тестированию и прочему.

В Go почти каждый аспект ежедневной работы, который раньше отнимал минуты и часы, стал занимать секунды. Я снова смог сконцентрироваться на написании кода, а не на борьбе с инструментами. Мой первый серьезный stress-тест для Go был на одном международном мероприятии, где мне понадобилось написать софт, который бы парсил псевдо-зашифрованный протокол, вычленял из него 60-кб xml-пакеты, разбирал их, извлекал нужные данные, кормил их небольшой стейт-машине, и генерировал выходные данные, отдавая в консоль, в файлы, и, желательно — на веб-интерфейс по веб-сокету.
Этот код я писал на коленке, и на Go (и это еще по ходу изучения stdlib) это заняло у меня около суток — большая часть времени ушла на разбирание протокола. Но я ни на минуту не отвлекался на проблемы языка, на лишние обертки и геттеры/сеттеры, на то «как это делать по-правильному» и «как выравнивать отступы». При этом я тут же создавал для каждой функции тесты — благо, это занимало не больше пары минут.

И это был реально глоток свежего воздуха после последних лет мучений с С++ и Python. Я снова получал удовольствие от самого процесса написания кода, и я был чертовски продуктивен. Сперва я сам не поверил, что вот эту, хорошо структурированную программу (там было 5 пакаджей, из которых два — эмуляторы источника данных и прокси-дупликатор), покрытую тестами, документированную(!), понятную и читабельную — я написал почти за сутки, и это при том, что я походу еще и открывал для себя новые библиотеки stdlib, изучая документацию. При этом я совсем не хардкорщик с феноменальной памятью, и не набираю на клавиатуре 800 символов в минуту.
И меня ошеломило, когда я попытался представить, сколько времени у меня ушло бы на подобную по качеству и понятности реализацию на С++.
Эта программа работает, кстати, до сих пор, на нескольких точках, и работает как часы. А да, и писалась она на макоси, а работать должна была на windows.

Но к чему я это всё вспомнил? Сейчас я использую Go ежедневно, в нескольких больших проектах, и всё также ежедневно наслаждаюсь огромной продуктивностью, которая появилась в Go. Если вы цените выражение «время — деньги», то продуктивность тут — прямой синоним слова «деньги». Для меня, по крайней мере.

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

И вот, на фоне всего этого, подходит коллега или анонимус в интернете, и говорит — Go — сакс, потому что «там нет эксепшенов»/«там нет generics»/«там нет динамической линковки»/«там нет Хиндли-Милнера» etc. И ты такой, стоишь и думаешь первым делом — «стоп, а как же я без этого жил, если для человека это блокер?». Начинаешь глубже разбираться в теме, и понимаешь, что речь лишь о привычке. Кто-то потратил буквально годы жизни, чтобы научиться правильно использовать исключения, или решил, что программирование шаблонами — это некая ступень в программировании, ниже которой опускаться нельзя. И человек не готов отказаться от привычки, и тратит мое и свое время, чтобы мне доказать — что «да пошла она твоя продуктивность, главное — это наличие generics».

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

Извините за длинный комментарий, но как-то так.
У меня аналогичные ощущения появились когда после С++ я перешёл на Python.
Надеюсь Pyston сможет решить главную проблему Python — скорость (и то её вполне научились обходить).
Да, это причина, по которой народ массово ломанулся С++ в Python/Ruby в свое время — буст продуктивности. Но у меня с Python тоже сильно не сложилось — начиная от большой сложности с деплоем и пакаджингом и заканчивая, собственно, скоростью и прожорливостью. Тоесть, если С++ давал хорошую скорость, но маленькую продуктивность, то Питон — наоборот.

Но по ощущениям Go ближе к Питону — он «чувствуется», как динамически-типизированный язык, это правда. И, кстати, если верить общему впечатлению по статьям/комментариям в коммьюнити, то больше всего на Go переходит именно народу с Python и Ruby, а C++-хардкорщики воспринимают его в штыки.
Это тема активно обсуждается комьюнити, по результатам составили даже сводный док. Сейчас гораздо интереснее тема с SSA-компилятором.
Помимо чисто академического интереса («может ли язык скомпилировать сам себя»), который так или иначе возникает во всех языковых коммьюнити, и успеха в котором практически никто не добивался


Помоему какая-то ерунда, уже куча языков до них сделало тоже самое. Первое, что приходит на ум: fasm, coffeescript и многие многие другие.
UPD в конце поста добавлен по этому поводу.
Извиняюсь, не заметил…
Sign up to leave a comment.

Articles