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

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

Учитывая, что сейчас даже в некоторые смартфоны ставят 8-ядерные процессоры, рост производительности сдерживается трудностью распараллеливания вычислений. Спасибо за перевод, интересно почитать про goroutines.
Горутины — чудесная и простая вещь. Параллельность, обычно, добавляется несколькими строчками, включая очереди и всё такое.
Уговорили, попробую Go.
Прекрасный язык, ориентированный на распределенные задачи. Весьма удивительной оказалась его простота конструкций и устройство системы сборки проектов. Когда ты пишешь импорт, а исходники тянутся сами при сборке и кладутся так, чтобы структура была максимально иерархичной и понятной.
goroutines — не параллелизм, а асинхронность. В Go нет «вытесняющей многозадачности» для goroutines. Т.е. если выполнение происходит в один поток, и работает какая-нибудь вычислительная goroutine в течение очень долгого времени, то остальные будут висеть в очереди — час, два и т.д.
Пример:
package main

import (
	"fmt"
	"sync"
)

const N = 2000000000
const T = 8

func DoLong(msg string, group *sync.WaitGroup) (ret uint64) {
	fmt.Printf("Start: %v\n", msg)
	for i := 0; i < N; i++ {
		ret++
	}
	fmt.Printf("End: %v\n", msg)
	group.Done()
	return ret
}

func main() {
	group := &sync.WaitGroup{}
	group.Add(T)
	for i := 0; i < T; i++ {
		go DoLong(fmt.Sprintf("thread %v", i), group)
	}
	group.Wait()
}


В один поток (GOMAXPROCS=1) выдает что-то вроде
Start: thread 0
End: thread 0
Start: thread 1
End: thread 1
Start: thread 2
End: thread 2
Start: thread 3
End: thread 3
...

При параллельности a la многопоточности, сначала бы все стартовали, потом все заканчивались.
Да, про это действительно стоит сказать, что если вам нужна параллельность (а не асинхронность), то наверное Go — не лучший выбор из-за отсутствия вытесняющей многозадачности. Однако, если в вашем примере поставить, скажем GOMAXPROCS=8, то все потоки стартуют одновременно и не ждут друг друга. С другой стороны, разработчики языка Go явно предполагают, что в основном все будут пользоваться настройками «по умолчанию» и в том же App Engine приложения запускаются с GOMAXPROCS=1.
Однако, если в вашем примере поставить, скажем GOMAXPROCS=8, то все потоки стартуют одновременно и не ждут друг друга.
К сожалению, нет. GOMAXPROCS устанавливает лишь верхний предел, который среда исполнения не обязана использовать полностью. Например, на моей машинке с 2-я ядрами с GOMAXPROCS=8 и даже 12 сразу стартует только 5 горутин, остальные ждут.
Да, вы правы, я как-то не заметил, что на самом деле на моем компьютере (с 2 ядрами, но с HyperThreading) сразу стартовали всего 4 потока, а не все 8.
Это из-за того, что у вас в горутинах ничего сложного не выполняется. Начните что-нибудь считать и увидите прирост системных тредов в запущенном процессе.
Получается что-то типа nodejs но без callback hell? грубо говоря, если нагружается процессор, то на ядро идет один поток, а если сделать запрос к базе, то го сам передаст управление другой горутине без лишних телодвижений?
Да, без callback hell и с возможностью использовать все процессоры в системе (но без вытесняющей многозадачности, то есть, если N >= GOMAXPROCS горутин «зависнет» в вычислениях, то новые события не будут обрабатываться).
А полноценных потоков вообще нет? Чтобы, допустим, веб-сервер просто принимал запрос и клал его в очередь, пока горутины доберутся до его обработки. Даже если весь процессор занят.
Если «полноценность» потоков определяется наличием вытесняющей многозадачности — то нет, в Go нет полноценных потоков. Тем не менее, если у вас всё-таки ваш веб-сервер не упирается в процессор (что для компилируемого языка типа Go более, чем нормально), то «легковесность» потоков в Go это скорее плюс, чем минус.
Ну вообще-то не хотелось бы, чтобы какая-то ресурсоемкая операция устроила DOS. Упремся в процессор или нет, нельзя сказать в общем случае. Даже на очень мощном железе можно упереться.

Ну для веб-сервера можно поставить какой-то nginx, конечно. Но если речь не о http, а каком-то другом протоколе, то идея тащить вместе с логикой на Го еще и диспатчер на другом языке, мне как-то не очень нравится.
Если в вашем коде будет «бесконечный цикл», то с настройкой GOMAXPROCS=числоядер вы сможете нагрузить свой сервер полностью этими вычислениями :) и всё ещё обслуживать запросы клиентов. Если же таких процессов будет больше в какой-то конкретный момент времени, то, как мне кажется, вы делаете что-то не так, и в другом языке программирования будет в целом не лучше, потому что скорее всего ваш сервер в таком состоянии долго не протянет :).

Насколько я понимаю, разработчики языка вообще предполагают, что у вас будет запущено по одному инстансу демона на каждое ядро на веб-сервере, и между ними будет распределять нагрузку балансер (либо «железный», либо простенький а-ля на nginx). В текущем виде Go плохо годится именно для параллельных вычислений: он скорее представляет из себя, также как и Node.js, очень удобный фреймворк для однопоточного асинхронного программирования.
Ну вот пример, гипотетический сервис, куда приходит запрос типа service.com/getimg?id=123&w=300&h=400. Суть в том, чтобы запрашивать нужную картинку в нужном размере с ресайзом в реальном времени и кэшированием.

Могут быть 2 ситуации, либо картинка есть в кэше (тогда это только io), либо ее нет (тогда процессор + io потом).

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

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

Или что я не так понял?
На Go вы не сможете совсем просто так взять и начать делать ресайз прямо в том же процессе (на самом деле всё равно можете, сделав буферизированный канал размером N = «GOMAXPROCS-1», и сделав N горутин, которые читают данные из этого канала и выполняют ресайз).

Более логичным решением в этой ситуации будет иметь отдельный внутренний сервис, который может тоже быть написан на го и заниматься ресурсоёмкими задачами. Грубо говоря, разделить задачу на две — одна на I/O, а другая жрущая процессор, и сделать 2 разных процесса, которые общаются между собой. В Go это тоже очень легко и удобно делается.
Ну для веб-сервера еще куда ни шло — 2 процесса. Хотя и костыльное решение, даже если «удобно делается». А если делать gui для какой-то многопоточной процессороемкой операции, то без отдельного процесса даже кнопку с паузой не получится сделать.

Как по мне, это все-же крайней негативно сказывается на универсальности языка. Вытесняющую многозадачность не просто так придумали, иногда ее все-же есть смысл использовать.
Go всё же пока что позиционируется, как удобный язык для написания сервисов, а не как язык общего назначения. Что же касается вашего примера с GUI, как мне кажется, здесь тоже было бы логично делать ресурсоёмкие операции в отдельном процессе, которому просто посылать SIGSTOP / SIGTERM, если нужно осуществить паузу / остановку. Но графических библиотек всё равно для Go пока особо нет, так что о такой проблеме можно рассуждать только в теории :).
Вообще, у меня есть мысль написать на Go игровой движок. Для онлайн игры реального времени. Там будут и ресурсоемкие операции и те, которые требуют быстрого отклика. Перспектива разделения их на 2 процесса меня пока очень не радует, желательно общее адрессное пространство. Да и не уверен что все операции можно будет однозначно отнести или к одним или к другим (хотя, скорее всего, можно).

И вот что-то это желание у меня поубавилось после того, как начал детальнее копать эту многозадачность в Го. Сначала показалось отличным вариантом, а теперь вот подумываю о старом добром пуле потоков и языке типа С++.
Ну погодите, вы же не хотите иметь всё состояние игры исключительно в памяти и держать его в одном (и только одном) процессе на одном сервере? Разделение логики на несколько процессов, до определенного момента — это почти всегда хорошо и улучшает архитектуру и качество кода. Отсутствие вытесняющей многозадачности — это конечно, минус, но просто Go создавался для упрощения написания асинхронного, а не параллельного кода, и лучше его использовать именно так. Это годится не для 100% задач, но зато для тех задач, где он применим, писать на нём — одно удовольствие.
А если делать gui для какой-то многопоточной процессороемкой операции, то без отдельного процесса даже кнопку с паузой не получится сделать.
Если сильно постараться, то можно: runtime.Gosched.

Но это всё стандартный спор о кооперативной многозадачности против вытесняющей. Делали же «многопоточные процессороемкие операции» в Win 3.1, кто хотел.
В моём понимании, такие разные задачи вообще противопоказано в один сервер пихать. Ресайз надо делать отдельной внешней программой. Либо вызывать ее из сервера, а дальше ждать и IO, либо RPC, который со стороны сервера суть IO.
В текущем виде Go плохо годится именно для параллельных вычислений
Именно для параллельных вычислений Go годится вполне :) В вычислениях ведь не важно, началось ли исполнение какой-то горутины сразу или через 5 минут, важно насколько быстро всё закончится.

Чтобы, допустим, веб-сервер просто принимал запрос и клал его в очередь, пока горутины доберутся до его обработки.
А зачем принимать запрос, если собираешься только класть его в очередь? Уже есть очередь на прием запросов в listen (Server socket queue length). Если очередь переполняется, то значит, производительности сервера не хватает в принципе. Зачем дополнительно городить еще свою собственную очередь?
Ну всё-таки речь о другом: сервер на Go может не отвечать из-за того, что его CPU загружен на 100% и при этом конкурентность запросов едва ли больше 1 на ядро. При этом теоретически (и практически тоже) ничто не мешает ему продолжать отвечать на запросы, которые просто требуют I/O, немного понизив приоритет тем тредам, которые просто едят CPU. Если на сервере 8 ядер и у него load average = 8, то это состояние ещё очень далеко от критического и не является причиной перестать отвечать на новые запросы. Я лично лет 10 назад видел load average = 200 на сервере с двумя ядрами, и он продолжал работать и отвечать на новые запросы.
nodejs но без callback hell

это erlang
Go всё же компилируемый и императивный :)
И в Erlang всё-таки вытесняющая многозадачность :) И Erlang — это не только язык. Так что, Erlang — это совсем не «nodejs без callback hell».
nodejs как бы тоже не язык. Просто средствами Javascript без колбэков там не обойтись, а в Эрланге как раз такого не потребуется. Насколько я понимаю, то в Go тоже.
Сказанное вами, никак не отменяет сказанное мной.

По ряду параметров сравнивать Go с Erlang даже правильнее чем с Java.
Главное отличие от nodejs — возможность загрузить все ядра одним процессом.
Go сам распределяет goroutines по ядрам.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Пока в Go не появятся дженерики или любая другая альтернатива параметрической типизации, не буду его использовать.
Пока у машины не появится гидромотора и шагателей — не буду ездить.
Вас собственно никто и не заставляет…
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Теплый и ламповый
точно!
JAVA не интерпретируемая же, там байткод и jvm
НЛО прилетело и опубликовало эту надпись здесь
Go с большим отрывом выигрывает по времени запуска и по скорости работы, когда Java действительно работает в режиме интерпретатора (раньше на том самом сайте debian shootout было сравнение). Но, безусловно, после JIT-компиляции код на Java по сути особо ничем от кода на Go и не отличается — у обоих языков есть «исключения» с разворачиванием стека (в Go называющееся panic), проверки границ массивов и т.д. При этом Go значительно младше и у него пока что нет такого количества оптимизаций, как в JIT-компиляторе Java. Не очень понимаю, чего в этом такого удивительного :)
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Опять сферическое сравнение языков в вакууме, очень подозрительное к тому же. Интересно, в каком таком приложении Ruby в 2 раза меньше памяти занимает, чем Go.
Всегда языки со статической типизацией потребляют меньше ОЗУ чем языки с динамической.
Что тут удивительного?
Вот именно.
Ответ на ваш вопрос «в каком таком приложении Ruby в 2 раза меньше памяти занимает, чем Go» должен был быть «в любом».
Наоборот.
НЛО прилетело и опубликовало эту надпись здесь
Если смотреть строго на аспект типизации, то при динамической типизации метаданные объектов однозначно больше места занимают. В целом же в динамических языках меньше задумываются как о производительности, так и расходе памяти. Плюс всякий сахар типа замыканий в этом плане тоже кое-что стоит.
НЛО прилетело и опубликовало эту надпись здесь
Смотря как определять расход памяти. Если как максимальное кол-во данных, которые можно удерживать в определенной ограниченной памяти — не думаю, что Java проиграет. Кроме того, Go — не Java. Хотя я не знаю, какой там GC, может тоже прожорливый.
Reverse-complement же. Довольно ожидаемо, потому как тут все вычисления руби делает с помощью встроенных функций языка, скомпилированных. Вопрос в другом — почему тогда Ruby это делает так медленно?
Какие управляющие слои и слои инфраструктуры новейших технологий будут использоваться для обеспечения функционирования облачных сервисов? В течение двух лет большинство из них будет написано на Go


выходит гугл для инфраструктуры в основном go собирается использовать? т.е. та ниша на которой erlang сейчас развивается.
Так понял что андройд на go вряд переводить будут.
Эрланг — это как раз только инфраструктура, а ведь есть еще вычислительные процессы, которые в случае гугла выступают далеко не на последнем месте.
Go компилируется в один статический бинарный файл. Развертывание — это просто загрузка файл на сервер и его запуск. Не требуется установка дополнительных зависимостей.
Я успел запустить только один проект (и тот небольшой) в production на Golang, но то, что Golang компилирует в один статический бинарный файл — это просто супер охренненая фича, очень и очень упрощающая процесс развертывания.
До тех пор, пока вы не используете cgo, это действительно так. А вот с его использованием он в версии 1.1 компилировать статически не умеет, к сожалению :(.
DISCLAIMER: Ниже IMHO. Любителей всего нового, ООП и тд может ждать Butthurt

1. Узким местом почти всегда является база данных при росте нагрузки.
Нет, конечно, если, как делают некоторые, все алгоритмы пихать в скриптовые яызки, даже те, которые ДОЛЖНЫ БЫТЬ на стороне БД с точки зрения разделения ответственностей, то язык очень скоро будет узким местом. Супер-ООП там делать стремиться, например.
Как некоторые удивлялись, что Вконтакте, который всех рвет и прекрасно работает, оказывается, блин, даже без ООП почти написан. Не-тру. И ваще ПХП-говно, Тру — сразу писать на новом и неопробованном на деньги инвестора!

2. Не уверен, что если бы взяли, например, C/C++ и писали на нем, было бы хуже. То, что на Джаве было бы тормознее, программеры дороже и серверов больше, даже не берем.
А вот то, что рискнули — это, конечно, интересно, но несколько неоправдано (разве что хотелось потешить самолюбие и получить аргумент для споров с коллегами на форумах а-ля «мы пишем Хайлоад на Go, а вы — лузеры, потому что сидите на старье»).

По пункту 2 — зато они заполучили себе топ-специалистов, которые, как оказалось, были в поиске чего-то нового.
НЛО прилетело и опубликовало эту надпись здесь
1. почти всегда
2. я не писал на Go, да. не знал, что оно скриптовое, мой косяк. читал, что компилируемый язык, но не бросался смотреть, честно скажу.
на плюсах писал, хотя под веб мегапроектов — не писал. системный/прикладной софт, в основном.
сборка не является особой проблемой. хотя добавляет геммороя, никто не спорит.
не знал, что оно скриптовое, мой косяк. читал, что компилируемый язык
Да, компилируемый. Но не для всякого компилируемого языка сборка — PITA. Для Go есть удобная команда-обертка, которая собирает и запускает в одном флаконе. Учитывая скорость сборки, по ощущениям не сильно отличается от скриптового языка, но при этом менее компилируемым не становится.
НЛО прилетело и опубликовало эту надпись здесь
Да ради бога.

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

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

В общем, сколько там проектов-стартапов умирает, выжирает бюджет, заканчивается позднее на 200%+ — везде открываешь и тупо люди считают себя слишком умными.

Я простой чел в этом плане. Тупое и простое решение — лучшее. Некрасивое, но опробованное лучше новомодного, но необкатанного.
Может, я просто не делаю плюшевые проекты для забавы? Там пожалуйста, каждый развлекается, как хочет.
НЛО прилетело и опубликовало эту надпись здесь
Если в первом комменте я подумал, что, набрасывая, вы не поддадитесь на ответ, то во втором видно — человек не сдержался.
Scala, или, например, D — это критерий? (давайте тогда Haskell лучше) Я видел тонны говна на модных инструментах, которые когда-то продвигались как «гарантия уровня разработчика за счет высокого порога вхождения».

Мышление является гарантией профессионализма, язык — инструмент, который вы выбираете, вкупе со всем остальным. Благо у вас с опытом нормально, юнит-тесты дело хорошее.
Если человек не понимает, например, что такое цикломатическая сложность или IoC дальше заученных определений, пусть он трижды знает любой язык и мегакрутой синтаксис, как будет порождать неверно сделанный архитектурно или сплошной overengineering на любом языке с любым мегасборщником мусора и синтаксисом от кутюр. Например, человек прочитал GoF и зачитался stl и он теперь херачит везде паттерны.

То, что это усложняет архитектуру, ее поддержку, скорость введения новых людей и тд, помимо ухудшения обычных метрик, волнует 10%. 90% печалятся, что вышел Ya, а они все еще сидят на устаревшем языке Ty (а платят при этом ставшим де-факто и оттого полным говнокодеров языком Go, на котором уже миллион проектов)

За вас рад, извините, не хотел обидеть, если что. Мне вообще плевать на язык, нужно — берем и учить, парадигм не так много, синтаксис учится пара дней, а все нюансы в течение месяцев работы над реальными проектами. Просто выбираем под область задачи набор инструментов, процесс разработки/методологию и тд, если не знаем — спрашиваем у гуру, ну и какие-то новые технологии, да, можно применить. Тот же NoSQL, там где четко понятны задачи, условия использования и возможные риски. Или node.js, или тот же Питон.

Я уже года три как менеджер проектов, если что :)
И помимо вопросов как сделать, чего для меня давно не стоит в плане можно/нельзя/как именно (разве что AS я так и не освоил, всегда флэш радовал меня, но не лез в него); еще рассматриваю много вещей вроде:
а) а как поддерживать будет?
б) кто будет поддерживать?
в) как ввести туда новых людей?
г) классическая тема затрат и ROI
д) какое будет масштабирование проекта по функционалу, нагрузке и тд
е) что есть в дата-центре, за какие сроки мне купят, соберут сервер не на фре, допустим, а на Линуксе, чтобы поездатая Джава на нем полетела нормально
ж) это highload, а какая там будет схема балансировки? а БД? как организуем репликацию?
и даже такие
з)!!! а может тупо возьмем вот эту готовую опен-сорс и допилим ее на общее благо? зачем велосипед? или вон ту купим и все
и) А стоп, а точно это решит проблемы заказчика? может сначала что-то в консерватории? если мы делаем проект автоматизации разных печатных договоров — может, ну его в собаку, давайте лучше электронный документооборот внедрить и вывезем горы бумажного говна.

Конечно, это далеко не всегда и чеклист выглядит не так.
Но вектор, думаю, понятен :)
НЛО прилетело и опубликовало эту надпись здесь
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории