March 24, 2024

Тестовое задание ментор GO - Денис Давыдов @watchdog_timer

Вопросы:

  • Ниже даны три пункта, два из которых на выбор вам необходимо объяснить. Ваша задача — донести смысл так, чтобы ваши объяснения смог понять новичок. Все средства хороши (рисунки, гифки, аудио-объяснение, доп.источники), если они делают объяснения понятными.
    1. Рассказать про понятие контекста (context) в Go
    2. Что такое горутина и чем она отличается от тредов и процессов
    3. Что такое gob и зачем это нужно

Ответы:

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

Так же у контекста есть особые методы отмены. Существуют ручная отмена и отмена по таймауту. Зачем это может понадобится?

Представим, что завершение всего процесса обработки одной единицы продукции зависит от выполнения всех этапов. Пока мы не завершим этап #N, этап #1 не сможет принять новую единицу продукции. Но что если на этапе #2 в обработке что-то пошло не так? Например продукция застряла в обрабатывающей машине? Наше производство могло бы встать на вечно. Было бы удобно иметь механизм позволяющий отменить обработку. Именно за этим нам нужны context.WithCancel, context.WithTImeout и т.д.

context.WithCancel возвращает нам новый дочерний контекст и функцию отмены. Если ее вызвать все производные контексты будут отменены. context.WithTimeout действует похожим образом, только он может отменится, через заданное кол-во времени. Тем самым мы можем сказать - "Если обработка нашего запроса (продукции), не завершилась в рамках следующих 15 секунд, мы не хотим продолжать обработку, нам нужно отменить все последующие запросы".

2) Горутина это легковесный поток выполнения. Если продолжить развивать аналогию представленную выше - у нас на фабрике есть конвеерная лента марки "Goroutine". Пока у нас было не много заказов, одна наша лента вполне справлялась с заказами. Но вот дела фабрики "пошли в гору" и кол-во заказов увеличилось в разы. Одна лента все еще прекрасно выполняет свои обязанности, продукция выпускается. Только мы не успеваем делать поставки в сроки. Решено было купить еще одну лента марки "Goroutine". Теперь у нас есть две идентичные ленты производящие идентичную продукцию, которые делают это одновременно. Тем самым время производства общего кол-ва продукции сократилось в двое.

Если перейти от аналогий из сферы производства ближе к компьютерным технологиям, то наша горутина это абстракция выполнения задачи (поток), а физически эти задачи выполняются на процессоре. У операционной системы где работают наши программы есть понятие "поток". Это некоторая единица работы, которая может выполняться физически одновременно с другими такими же потоками на разных ядрах процессора. Только есть несколько проблем. Наши потоки тяжелые (8Мб для ОС семейства Linux) и для переключения с одного потока на другой операционной системе (если конкретней, то планировщику ОС) требуется произвести действие которое называется "переключение контекста". Если не вдаваться в подробности, можно просто сказать, что это довольно тяжелая операция для всей системы, по переключению режима из "пространства пользователя" в "пространство ядра ОС". Развивая идею потоков некоторые языки пришли к тому, чтобы ввести в свой рантайм свое понятие потока и свое понятие планировщика потоков. Подобная идея не обошла сторой и язык Golang, в котором появилась абстракция выполнения под названием "Горутина". Преимущество иметь в пользовательском режиме свои потоки - огромные. Мы можем сами реализовать свои потоки. Например в го потоки (горутины) весят всего ~2кб и при необходимости могут увеличивать (практически без ограничений) и уменьшать свой размер. Другой плюс в том, что мы больше не должны переключаться в "пространство ядра" для того планировать другие потоки. Планировщик языка го работает в пространстве пользователя, в отличии от планировщика ОС.

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


Вопросы студентов:

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

Вопрос:

1) Я собираюсь преобразовать строку в число: i, err := strconv.Atoi(foo) и он ругается на то, что "err declared but not used", как мне лучше поступить?

Ответ:

Привет! Ошибка говорит о том, что ты присваиваешь переменной err некоторое значение, которое далее нигде не используется по коду. В go подобные действия недопустыми, тебе всегда нужно использовать объявленные переменные. Ты можешь игнорировать второй возвращаемый параметр функции Atoi подобным образом:

i, _ := strconv.Atoi(foo)

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

Вопрос:

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

Ответ:

На го в этом тоже нет ничего сложного. Как ты правильно заметил(а), для этого нужно использовать пакет math.

Пример:

package main import ( "fmt" "math" ) func main() { number := 3.14159 rounded := math.Round(number*100) / 100 fmt.Println("Округленное число:", rounded) }

В данном сниппете используется функция Round из пакета math, которая округляет число до ближайшего целого. Мы умножили наше исходное число на 100, что переместить для знака после запятой в целое число, зачем округляем его до ближайшего целого и делим опять на 100 для возвращения десятичной части.

Если нужно просто вывести на экран число можно просто воспользоваться форматированием:

fmt.Sprintf("%.2f", number)

Представьте, что вам надо проверить проект студента. Дайте студенту обратную связь по этому коду в письменном виде.

1) имя пакеты "bad" не является информативным

2) В функции Line присутствует использование переменной stringEmpty которая нигде не определена.

3)Функция Line не проверяет длину строки перед обращением к индексам. Это может привести к выходу за границы массива.

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

5) Код не содержит комментариев появняющих назначение функций.

6) В функции extractFlightLevel игнорируются ошибки

7) Функция Line имеет не ясную семантику. Нельзя понять, что делает данная функция предварительно не заглянув в ее код. Лучше переименовать ее во что-то на подобии - "SplitLine"