Pull to refresh

Comments 52

Спасибо! Насколько я вижу, уровень выше (и ценнее!) среднего youtube-ролика а-ля «основы Golang» или «как мы уменьшали stop-the-world в GC»
А ещё советую в заголовок, текст или в теги добавить «golang». Это общепринятая рекомендация для именования материалов, чтобы было проще гуглить.

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

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

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

В наше время есть серверы, не использующие ту или иную реализацию параллельного выполнения запросов от клиентов?

В наше время есть программы, которые работают не на сервере.
В наше время есть cli-утилиты (например, сконвертить один файл в другой)
В наше время есть однопоточный bolt.

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

На Go действительно можно быстро писать код, и не только многопоточный/конкуррентный.
Прошу заметить, что это не означает, что нельзя программировать на D/Rust/Scala/etc.
Справедливости ради озвучу (хотя тут все это понимают), что любой сервер под капотом использует многопоточность в том или ином ей виде. Go-шный net/http сервер — тоже. Однако можно написать http сервер на Go (на основе net/http) и в коде не будет ни одного вызова go funcName().

Я уточнял исключительно про серверы.

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


package main

import "fmt"

func int64Sum(list []int64) (uint64) {
    var result int64 = 0
    for x := 0; x < len(list); x++ {
        result += list[x]
    }
    return uint64(result)
}

func int32Sum(list []int32) (uint64) {
    var result int32 = 0
    for x := 0; x < len(list); x++ {
        result += list[x]
    }
    return uint64(result)
}

func int16Sum(list []int16) (uint64) {
    var result int16 = 0
    for x := 0; x < len(list); x++ {
        result += list[x]
    }
    return uint64(result)
}

func int8Sum(list []int8) (uint64) {
    var result int8 = 0
    for x := 0; x < len(list); x++ {
        result += list[x]
    }
    return uint64(result)
}

func main() {

    list8  := []int8 {1, 2, 3, 4, 5}
    list16 := []int16{1, 2, 3, 4, 5}
    list32 := []int32{1, 2, 3, 4, 5}
    list64 := []int64{1, 2, 3, 4, 5}

    fmt.Println(int8Sum(list8))
    fmt.Println(int16Sum(list16))
    fmt.Println(int32Sum(list32))
    fmt.Println(int64Sum(list64))
}

Тоже самое на D. В которому впрочем поддержка этих же легковесных потоков тоже есть.


import std.stdio;
import std.algorithm;

void main(string[] args)
{
    [1, 2, 3, 4, 5].reduce!((a, b) => a + b).writeln;
}
но совершенно не подходит для обработки данных

У каждого свои данные. Я вот пишу что-то типа Socorro, но с поддержкой emscripten. Данными являются файлы символов, минидампы, то что сваливается в GlobalEventHandlers.onerror.

UFO just landed and posted this here
Это все-таки разные вещи. Как минимум, в файберах управление переключается явно.
Yield нужно расставлять руками (в golang умный шедуллер) и распределением фиберов по тредам придётся, опять же, заниматься руками. Штука всё равно хорошая и D куда более мощный и приятный язык, чем Go, но всё-таки горутины куда более продвинуты.
Простите, но Ваш пример, демонстрирующий «невозможность организовать на golang обработку данных», не выдерживает никакой критики. Лаконичность кода на D — да. C тем же успехом можно написать строчку на JS
[0, 1, 2, 3, 4].reduce(function(previousValue, currentValue, index, array) {
  return previousValue + currentValue;
});
и сказать, что JS аж на пять строк короче, чем D…

А как насчёт сопровождения такого кода? Как насчёт отлова ошибок с данными на этапе компиляции? Тесты производительности гоняли?
Так писали лет 10 назад. Сейчас на JS эта задача решается гораздо проще:
[0,1,2,3,4].reduce((item, sum) => item + sum);


А вот вам пример на php:
array_sum(range(0, 4));


Вывод: php круче всех :)

В Вашем примере на D только один массив непонятного размера и бизнес-логика (суммирование) не вынесено в отдельную функцию. Если же создать 4 массива с элементами разных размеров и не инлайнить функцию суммирования (а написать template, который будет понимать разные типы), то кода будет чуть больше… Но в целом Ваши негодования понятны — отсутствие в стандартной библиотеки функции reduce (есть сторонние реализации) и отсутствие generic-ов — на эту тему уже много написано, даже авторами языка.

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


Даже Python на фоне Go смотрится куда более продуманным и совершенным языком.

можете привести пример где go «совершенно не подходит для обработки данных»?
Да, в примерах Go выглядит именно так, но в реальных проектах редко спотыкаешься о то что под каждый тип надо свой метод писать. У нас много разных сервисов на Go, и таких функций как в примере, ну может 2-3 от силы, а 2-3 функции в common это примерно 0% от кода проекта.
Соглашусь. Только на низком уровне с этим есть сложности и при потребности в максимальной прроизводительности: иначе же можно спокойно жить с fmt sync.map и прочим, принимающим и отдающим interface{} и не столкнуться с проблемами, ни кода ни производительности.
Мне кажется, что желание дженериков везде и всегда, сродни преждевременной оптимизации или неоправданному расширению задачи: надо было сделать для одного типа, но программист пробует написать обобщенный код.
Дженерики нужны, конечно, кодогенерация не помогает всегда, да и код усложняет в разы, как и отладку сгенерированного кода. И в самой стандартной библиотеке она не используется, то есть это решение и разработчикам golang не сильно нравится.
Но да, дженерики не настолько важны в действительной жизни. Рабочий код пишется и без них.
Это слишком «притянутый за уши» пример, как по мне, например, лучше один раз создать пакет sum (Int8, Int16 etc) и использовать его в проекте
package main

import "sum"

func main() {
   println(sum.Int8([]int8 {1, 2, 3, 4, 5}))
}


чем пытаться понять из какого пакета прилетела функциональность writeln или reduce (соответственно, чем больше проект и больше пактов, тем сложнее, опять же для меня, все это поддерживать), так что только на основании этого я бы не стал утверждать, что он (Go) категорично не подходит для обработки данных

ЗЫ: и у D и у Go есть свои плюсы, но Go, в моем случае, предпочтительнее в силу своей очевидности

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

Вы потролить зашли? :) Запрос в гугле «golang обработка исключений» выдает ответ на ваш вопрос на stackoverflow и несколько статей (в том числе и на хабре) про обработку ошибок в go.

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

Я понимаю, почему вы ищете исключения в go — «привычный механизм», я не понимаю зачем? Например, вы привыкли ездить на велосипеде, видите как другие ездят на самокатах и удивляетесь — зачем они ногами от земли отталкиваются, есть же классная штука — педали, которые можно крутить… и ищете педали на самокате… даже где-то видели возможность прикрутить педали к самокату. Зачем? Если для вас важен механизм исключений при разработке, а обработка ошибок как возвращаемых значений в go кажется вам неудобной, не изучайте go. Есть множество других языков с исключениями.
Мне вот не понравился rust, не смог привыкнуть к его «свистульками и погремушкам», причем на уровне ощущений и эмоций, т.е. я не смогу объяснить — чем именно не понравился. Нет, так нет, я и не читаю статьи про rust.
Минусуют фанаты rust'а? Это я неудачный пример привел… холиварный. Буду иметь в виду.

А что раст? Там тоже "нет исключений". Просто перестроится сложно и не всегда понятное даёт ли это хоть какие-то преимущества. Люди привыкли жить с исключениями и находят в этом определённое удобство. Тут надо показать преимущества другого подхода, а не просто предлагать забыть о предыдущем опыте.

Я не предлагаю забыть предыдущий опыт. Я немного о другом. В каждом языке есть свои особенности и, касаемо go, у разработчика нет выбора в подходе обработки ошибок — нельзя выбрать «go с исключениями» или «go с возвращаемыми ошибками». Выбор есть только выше уровнем — go или «не go». Если кому-то важны именно исключения, значит go следует вычеркнуть из списка «следующий язык программирования для изучения». Если жизнь не мила без дженериков — аналогично. Я об этом.
А «не фигово было бы изучить go, но в нем обработка ошибок какая-то неудобная...» я не понимаю. После подобного хочется спросить «Ииии?!» Дальше-то что? Если человек хочет узнать, как эта неудобная обработка ошибок работает и как ей пользоваться, ну, так «google в помощь» — информации навалом.
А про раст — мне неважно, есть там исключения или нет; если у меня хватит терпения и времени я приму его модель и неважно — насколько она отличается от go, python, php, lua (других языков я не знаю).
Все так. Вы правильно в начале написали.
Так сказать для программиста/инженера выбор инструмента основываясь на эмоциях не самый лучший подход.
Полностью с вами согласен. Но я себе выбирал не инструмент для каких-то конкретных задач, а тему для саморазвития, чтобы мозги «не кисли». Поэтому не стал «копать» — что именно меня не устроило в rust'е. По мелким админским задачам python'а хватает «за глаза», т.ч. я и Go пока не нашел применения на работе, к сожалению.

Для человека, работавшего со, скажем так, Фортран и Си-подобными языками, некоторые варианты, предлагаемые Go, в частности возвращение из функций двух значений, одно из которых является и признаком, и сообщением об ошибке, являются куда более удобными, чем привычное либо возвращение ошибки магическим числом, либо падение процесса. Привычные по С++ подобным языкам исключения с раскруткой стека вызовов чащего всего используются не по назначению, не для обработки исключительных ситуаций, а для ветвления в зависимости от каких-то определенных условий.

Простите, но уровень лекций — «ниже плинтуса». Может, это слишком субъективно, но я не смог досмотреть ни одной лекции. Хватило терпения только на 3. Я понимаю — парни волнуются, они разработчики, а не преподаватели. Но тем более тогда лучше сделать публичную версию специально отснятой — с монтажем, дублями и т.п. Видео и так очень отстает от книг в плане скорости подачи информации, а в этих лекциях скорость становится просто черепашьей, к сожалению. ИМХО, книга Кернигана и Донована за аналогичное время даст больше информации и основы go будут понятнее.

Уровень лекций как способа подачи материала или самого материала?

Как способа подачи материала, в первую очередь. Трудно оценить качество материала при низком качестве его подачи.
Во первых, мое почтение за большую работу. Сейчас это самый полный материал по Golang, по крайней мере, на русском языке.
Но для пробы посмотрел вторую лекцию и был удивлен: в лекции рассматриваются вопросы, которых или не существует или они по-другому работают в go. Рассмотрена передача параметров по ссылке и значению, но в go есть только передача по значению; предупреждается о переполнении стэка — ну это возможно, если всю память переполнить, впринципе…
Рассмотрена передача параметров по ссылке и значению, но в go есть только передача по значению
В Golang есть передача по указателю ( http://golang-book.ru/chapter-08-pointers.html ) ну и для особых случаев пакет unsafe если уж действительно надо поработать на низком уровне.
Указатель не есть тоже самое, что ссылка.
Можно сделать указатель, но в функцию его передашь все равно по значению. С unsafe то же самое. Ну будет uintptr — это не ссылка, а вполне себе значение.
Давно я не брал в руки шашки.., но по сути, ссылка, это неизменяемый указатель… Можете написать пример кода на Go, в котором именно ссылка а не указатель потребовались, и так, чтобы именно существенно? (В вопросе нет иронии, плз, поделитесь проблемой).
Ну проблемы нет, есть неверный материал в лекциях, в частности из-за непонимания того, что в go есть только передача по значению можно написать такой неверный код
Чуть нагляднее даже так
Если считать, что в go есть передача по ссылке и типы slice, map и chan ссылочные, то такую ошибку сделать легко.
Идея хорошая, но как уже писали — качество хромает, некоторых лекторов просто невозможно слушать. Если их научить не делать ээээ, убрать слова-паразиты и тп, все получится. Но хоть какой-то контент на русском стал появляться по гоу, за это спасибо.

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

Спасибо. Передала преподавателям.
Спасибо за видео. Отложенный эффект сделает своё дело
Sign up to leave a comment.