Задача из Ozon: Golang собеседование
HTML-код
- Опубликовано: 16 окт 2023
- Мой курс по разработке микросервисов: clck.ru/389FPG
Мой Boosty: boosty.to/olezhek28
Linkedin: / olezhek28
Telegram-канал: t.me/olezhek28go
В этом ролике мы разберем популярную задачу с golang собеседований. Golang нынче стал хайповым языком программирования и многие люди переходят на него с других языков. Поэтому и важно научится решать эту golang задачку, чтобы не ударить в грязь лицом на собесе для golang разработчика. Можно сказать - этот ролик небольшой урок по golang, потому что для понимания некоторых аспектов этой задачи нам нужно заглянуть в go поглубже. На практике golang порой бывает неочевидным и важно понимать, что за этим стоит. И ещё, в конце ролика я накинул пару вопросов на подумать для вас. Смотрите до конца и пишите свои ответы в комментах.
Олег вырост, когда-то смотрел собеседование на middle разработка, а уже ведущий разраб и сам уже контент пилит)
Как говорится: «все течет, все изменяется»
Ждём курсы )))
Очень понравился стиль изложения, и задачка интересная. Хотелось бы видеть еще подобные видео с Гошными премудростями )
Спасибо:))) думаю еще будет
Thanks for detailed explanation
Did you read subs?) Is it helpful?
I understand Russian, I just have difficulties with writing, so I did not use subs. @@olezhek28go
Interesting:) Where are you from?)
Олег объясняет как боженька. Так чётко и просто всё разложил, спасибо!
Спасибо, рад что понравилось:)
Очень понравилось, спасибо
Здорово!:)
очень понравился стиль изложения, поэтому было бы круто увидеть больше видеo про подобные тонкости🙂
Спасибо:) буду стараться делать новые видео
Требуем больше познавательных роликов!
Если получится, то в эти выходные буду снимать :)
for range возвращает index, value. Если запрашиваем одну переменную, то индекс. Поэтому 0,1,2,3,4
верно)))
Покажи конечный продукт где такое применяется с горктинами и каналами !! А то весь Ютуб показывает код , а где это работает и какую пользу несёт не ясно . Чтобы понимать зачем вообще такое спрашивают
@@aleksanderpeshkin2266 без разницы от того понимаем мы или нет зачем такое спрашивают - спрашивать все равно будут) и если хочешь устроиться - знать должен
Очень классный формат, хочется больше таких примеров) Прикольно что сначала можно было попробовать самому решить задачу, а потом увидеть где не прав)
Спасибо) думаю буду периодически делать такие ролики
Формат отличный. Покачали задачу. Так намного интереснее
Спасибо, рад что зашло:)
респект за инфу, про то что в замыкания по прокидываются переменные, не знал, прокидывал всегда все через аргументы функции
Круто, что узнал что-то новое:))
Спасибо, и формат супер и было полезно. Пожалуйста, не останавливайся!)
Меня на собесе ещё спрашивали как оставляя горутины сделать, чтобы числа выводились последовательно и желательно было набросать и объяснить пару вариантов
Спасибо:) и какие варики в голову пришли?
@@olezhek28go через каналы или wg.Wait() поставить в конец цикла
@@olezhek28go мне кажется тут можно канал использовать и читать из него числа
будут ли ролики по внутрянкам го? типа работа gc, аллокаторы памяти, планировщик горутин и тд
Все может быть, но пока точно ответить не могу)
Спасибо за рассказ о фигче loopvar.
Наконец то нашел повод попробовать:)
@@olezhek28go Штука интересная, но она вызывает у меня настороженность. Уже представляю ситуации, когда девелопер пишет код и этой активированной функцией, а в билд пайплайне это причуда не активирована - и код уходит в продакшн.
С февраля это будет по дефолту в языке
Привет. Мне предлодили оффер в озон. Можешь рассказать чтото про перфоманс ревью и индексацию зп? Думаю отказаться только изза этого. Начитался отзывов на дримджоб
Напиши мне в личку в тг - olezhek28
1)горутины не параллельны, а конкуренты, то бишь рантайм под коробкой решает как переключаться между ними, пока одна горутина спит другая работает
2)мы берём индексы слайса, п не сами значения, поэтому такое и поведение
1) ну врядли на одном принте будет какое-то переключение между горутинами
по поводу первого вопроса
все будет работать абсолютно также как и на нескольких ядрах, никакой разницы нет с точки зрения планировщика. 4 выводится первой потому что у нее по сути кеш прогрет больше всего. там вроде как есть стек размером в один как раз для этого, чтобы брать оттуда задачи первыми. Правильно?)
Ага, все так)
интересно, автор видео согласовывал нейминг видео? не будет ли каких-либо юридических проблем, так как Олег ранее работал в Озон?
Это ж больше внимание привлечь, задачу то эту где угодно спросить могу , ибо уж очень популярная)
Когда примерно будет старт курса по разработке микросервисов?
Второй поток сейчас заканчивается, а новый будет уже после НГ думаю
Такое поведение (4, 0, 1, 2, 3) повторяется. У меня предположение, что горутины с 0 по 3 ставятся в локальную очередь. А горутина с 4-кой ставится в LIFO часть глобальной очереди и оттуда и исполняется первой (потому что она уже есть в кэше процессора), а уже за ней те, что локальной очереди.
Полагаю так и есть:) кстати, случаем нет статейки про это под рукой? а то я этот дивный факт знаю, но вот пытался статейку найти, чтоб кидать людям и обычно просто про очередь упрощенно пишут
@@olezhek28go постарался поискать где я эту информацию взял, но не нашел сходу
Размер локальной очереди 256. А так гуглить runnext, это поле у P. Новые горутины получают приоритет, при этом используют остаток временного слота горутины-создателя. Каждый go stmt забрасывает новую горутину в runnext и шедулер возьмет сначала горутину из runnext и только потом начнет разгребать локальную очередь.
На русском я не находил ни одной толковой статьи. Есть на английском. Можно почитать с браузерным переводчиком. Только тутуб комментарии с ссылками не пропускает.
@johnsc4521 странно, что ссылки не пропускает, вроде должен
Спасибо, позновательно!
17:40 Можно предположить что планировкщик задач GO в любом случае использует какой то алгоритм для выбора порядка выполненния задач в отведенное ему процессорное время. И он не просто выполняет их по порядку, а например пытается "усреднить" нагрузку дергая из разных частей списка задач.
15:59 Если правильно понимаю первая переменная при исользовании range - индекс записи. ( индек, значение := range слайс)
А вот почему такой вывод в 22 версии непонимаю. При планировании горутины делается снимок используемых переменных?
Если выводить адрес переменной в 21 и 22 версии, наблюдается разное поведение. В 21 он в каждой горутине одинаковый. В 22 - каждый раз новый адрес. Причем как если передавать его как аргумент и если через замыкание. Не наткнулся в патч ноуте с ходу на это. Есть какой то док описывающий поведение?
Загугли "Fixing For Loops in Go 1.22", ещё там внизу статьи есть раздел More Information с ссылками на дизайн-док и фак.
А если вкратце и на пальцах - раньше переменная цикла имела областью видимости весь цикл, а теперь областью видимости будет только итерация цикла.
не, там прикол том, что в шедулере у каждой М есть очередь фифо и одноэлементный лифо, мы в него кладем последний элемент, но и брать будем сначала из него
Чтоб в выводе было 1-5, надо так: for _, i := range
Верно!:)
@@olezhek28go Спасибо за задачки!:) Кстати, я решил оставить в Print() вывод адреса WaitGroup. Результат меня удивил 0_o Адреса либо были разными все, либо частично были совпадения, либо все одинаковые. Вопрос: Потому ли это, что WaitGroup на стек попадает?:)
Что-то не совсем понял, то есть вывод ключей или индексов слайса, дает последовательность?
@@Erdaulet100 Привет)
У слайса нет ключей (ключи есть у map). Слайс - это абстракция над массивом. У массивов и слайсов есть элементы, а у элементов есть индексы. В Go существует 2 способа пройтись по слайсу:
1) использовать обычный цикл for:
for i := 0; i < len(things); i++ {
things[i] =
}
2) использовать цикл for range (что работает как с последовательностью в Python, но в Go это всегда либо слайс, либо массив):
for i, v := range things {
// i - это копия индекса текущей итерации 0...len(things)-1
// v - это копия значения элемента things по индексу i (как будто v = things[i])
}
Записывать в копии i и v нет смысла в цикле for range. Они используются для чтения из них. Если нужно записать в элемент слайса в этом цикле, то, как обычно, используется запись things[i] =
Стиль изложения - огонь! На Go не пишу, но почти ни с чем не ошибся. Могу только предположить, сколько тысяч человеко-лет гоферы потратили на дебаг таких ошибок))
Впрочем, этот наш простой пайтон - тоже нифига не простой)
Спасибо:))) на самом деле многие ошибки подобные в бест практисах учтены и некоторые люди не косячат в них и даже не понимают почему ахаха
при log.Fatal defer не вызовется, поэтому пишет log.Panic )
Как варик)
Тот случай, когда основной синтаксис языка видишь быстрей, чем читаешь в учебнике🥴
Это хорошо?:)
Всё, теперь в озоне разрешили defer ?))
А запрещали?
На сколько известно в GO рутины легковесные (2к) и одном ядре может быть несколько рутин, поэтому параллелизм сохраняется даже с одним ядром, поэтому и вывод такой
Все так, но горутины то в очередь последовательно кладутся)
параллелизм невозможен на одном ядре))) ядро физически не может выполнять больше одной операции за один тик процессора
@@kidayano всё так, если мы гипертрединг не берем в расчёт)
Задача топ! Да, простая. Да, боянистая. Но даже на таких задачах можно завалиться.
Ага, иногда люди на ней такую базу выдают)
Всё элементарно просто, 4 ядерный процессор. Поэтому и получается такая последовательность. Четвёртое ядро 1, 2,3,4
Специально не смотрю комментарии. Верный ответ?
А это на какой вопрос?) про ситуацию с го макс проц?
азазза голову ломал, откуда 0 и нет 5
угар, всем бобер кувра!
Ахаха
пока смотрел видео, постоянно переключался на телеграмм свой думал что мне пришло сообщение и никак не мог понять, wtf, потом как дошло)
Там реально слышно?) я че-то при монтаже не заметил(
Олег, можно консультацию получить у тебя, по дису например, если да то где контакт спросить?
В телеге olezhek28
дейстивительно боянистая задача. на первом же собесе по го ее спросили)
Ага) тем и удивительнее, что еще не все научились ее решать
Последняя загадка настолько меня впечатлила, что я понял что не писать на голанге выбор правильный 🤨 даже JavaScript привели в чувство, по сравнению с этим вашим Го
Да на самом то деле это больше интересный момент, чем что-то важное на практике
Это задача для миддла или джуна?
Да такое и на сеньора спросить могут, просто ответ разной глубины устроит и конечно эта задача будет не единственной:)
хех, а я думал алгосики спросят на го, а нет - собес как старые джава собесы, где квиз на квизе
Ахаха алгосики в другой секции)
нет тайной ложи, есть явная лажа, если задаваться вопросом назовите где может быть использован этот алгоритм на практике или в жизни, как часто этот алгоритм пользуется в проектах? а на собеседованиях обычно спрашивают то что сами в компаниях не пользуются и тогда появляется мысль может это не имеет значение от слова совсем
А вы это мнение со стороны высказываете или сами на гошке пишете?) на мой взгляд почти все аспекты языка, которые вскрывает эта задача, регулярно встречаются на практике.
@@olezhek28go побольше практических примеров для каких целей и я Вас благодарю и целую монитор с вашим кодом
загадки для джунов ))) кто ж так range пишет))
вопрос в догонку к GOMAXPROC(1). А какой порядок будет если мы перед wg.Wait() time.Sleep(1) добавим?)
А если потом перед time.Sleep(1) добавим runtime.Gosched() ?)
Исходя из моих прикидок, кажется что такой же, но может что-то упускаю) хотя…
Слип это системный вызов, стало быть впору переключить контекст, дальше идет выполнение горутин в том же порядке и даже если секунды не хватит, то маин горотина же по идее залетит в глобальную очередь и оттуда наврядли раньше успеет вычитаться чем остальные, 1 к 61 как никак) но это так мысли в слух) надо завтра поиграть
@@olezhek28go а вот тут и есть прикол ) Если делать слип без Gosched, то вывод будет 0 1 2 3 4, а если хоть раз до этого сделать Goshed, то уже 4 01 2 3 )
Если просто порассуждать т.к. истинная причина не ясна, то получается при Sleep последний стек будет не не наших горутин, а слипа, поэтому исполнение горутин будет FIFO, а Gosched в свою очередь переключит на последнюю вызванную горутину т.е. будет 4 0 1 2 3 )
Получается 0,1,... Наверное потому что schedule прежде чем жертву выбрать проверяет таймеры. Видимо sleep(1) проходит слишком быстро и schedule опять выбирает main горутину в checkTimers. Можно увеличивать время сна и в какой-то момент 4 из runnext запуститься, но если таймер успеет сработать, то main горутина через checkTimers может влезть вперед local queue, в любом месте. Если Gosched добавить, то текущая горутина уйдет в конец local queue, а scheduler возьмет 4 из runnext. В данном примере с глобальной очередью вообще ничего не должно происходить, ведь capacity локальной очереди 256 + timers heap у каждого P свой.
P.S. Sleep(1) это не 1 секунда, а 1 наносекунда. Duration в наносекундах. Там где duration не стоит указывать просто int, об этом 75 глава 100 Go Mistakes
Я видать вечером не заметил, что там секунда не стояла) забавно то, что с секундой все ведет себя также) я из этой предпосылки исходил
@@olezhek28go оу... слип 1*time.Second это перебор для смены контекста) просто time.Sleep(1) ) вот такая у нас уличная магия... в рот мне ноги.
Я ещё не понял loopvar. Что это?
это просто значение переменной окружения, которая позволяет врубить экспериментальный функционал языка) с февраля это будет в дефолтной версии языка
а откуда взялся 0?
С нуля же цикл)
@@olezhek28goа точно, я подумал i это значения массива
1
поздравляю)
Братик это хайлвл, это только учу гошку мне трудно понять что происходит =/
Придет время и все поймешь;)
@@olezhek28go да это вообще фэйл =/ я знал питон, пришел в универ там были ++ и java, я пострадал может недели 2 и все ок стало. Java даже понравилась, начала ковырять Go, начитался комментариев “go самый простой язык ко ко” но пока мне он больше боли доставляет =/
Устарело) Теперь итератор per-iteration, а не per-loop
upd: а, блин, досмотрел)
А загадка про конкурентность vs параллельность.
Ахах)
Загадка про один тред то?
В js вообще всего один поток. И тем не менее конкурентности хватает)
серьезно? ноги целовать за знание элементарной базы? что не так в этом мире? хотя чему тут удивляться безработному программисту с 20 летнем стажем
Ну камон, ирония же была:)