Golang | Вопросы собесов
4.75K subscribers
32 photos
972 links
Download Telegram
Как каналы устроены в Go ?
Спросят с вероятностью 92%

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

Основы

Могут быть типизированы, что означает, что канал может передавать значения только одного определённого типа. Они могут быть объявлены и инициализированы с помощью ключевого слова chan:
ch := make(chan int) // Канал для передачи значений типа int


Отправка и получение данных

Для отправки значения в канал используется оператор <-:
ch <- 10 // Отправка значения 10 в канал


Для получения значения из канала тот же оператор используется, но в другом контексте:
value := <-ch // Прочитать значение из канала и присвоить его переменной value


Блокировки

Особенностью является то, что операции отправки и получения данных являются блокирующими:

Если горутина пытается отправить данные в канал, она блокируется до тех пор, пока другая горутина не прочитает эти данные.
Аналогично, если горутина пытается прочитать данные из канала, она блокируется до тех пор, пока другая горутина не отправит данные в этот канал.

Буферизация

Могут быть буферизированными, что означает, что они могут хранить ограниченное количество значений без необходимости немедленного получения. Буферизированный канал инициализируется с указанием размера буфера:
ch := make(chan int, 5) // Буферизированный канал с размером буфера 5


В буферизированном канале отправка не блокируется до тех пор, пока буфер не заполнится, и получение не блокируется до тех пор, пока буфер не опустеет.

Закрытие каналов

Каналы можно закрывать, если больше нет необходимости отправлять через них данные. После закрытия канала нельзя отправлять данные, но можно продолжать получать данные до тех пор, пока канал не опустеет:
close(ch)


Проверка на то, что канал закрыт и данные исчерпаны, возможна в операции чтения:
value, ok := <-ch
if !ok {
// Канал закрыт и все данные получены
}


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

👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 349 вопроса на Golang разработчика. Ставь 👍 если нравится контент

🔐 База собесов | 🔐 База тестовых
👍17
Что такое горутины ?
Спросят с вероятностью 83%

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

Особенности:

1️⃣Легковесность: Горутины занимают значительно меньше памяти по сравнению с традиционными потоками операционной системы. Один процесс может поддерживать тысячи или даже миллионы горутин благодаря их эффективному управлению памятью и ресурсами.

2️⃣Масштабируемость: Планировщик в Go автоматически распределяет горутины по доступным процессорным ядрам, оптимизируя использование ресурсов и увеличивая производительность программы.

3️⃣Простота использования: Синтаксис для создания горутин в Go очень прост. Достаточно использовать ключевое слово go перед вызовом функции:
go myFunction()


Этот вызов создаст новую горутину, которая начнет выполнение функции myFunction.

Допустим, мы хотим одновременно обработать несколько HTTP-запросов. Вместо создания одной горутины на каждый запрос, мы можем написать так:
func handleRequest(request *http.Request) {
// Обработка запроса
}

func main() {
requests := fetchRequests() // Предположим, это функция, которая возвращает список запросов
for _, req := range requests {
go handleRequest(req)
}
}


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

Горутины — это эффективный и масштабируемый способ реализации параллельного выполнения и асинхронной обработки в Go. Их легковесность и простота использования делают их идеальным выбором для современных многопоточных приложений.

👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 349 вопроса на Golang разработчика. Ставь 👍 если нравится контент

🔐 База собесов | 🔐 База тестовых
👍81
Что такое интерфейсы ?
Спросят с вероятностью 75%

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

Основные характеристики:

1️⃣Декларативная природа: Интерфейс объявляется как набор методов, но без их реализации. Классический пример — интерфейс Reader из пакета io, который определяет метод Read:
type Reader interface {
Read(p []byte) (n int, err error)
}


Любой тип, который реализует метод Read с такой же сигнатурой, считается реализующим интерфейс Reader.

2️⃣Неявная реализация: В отличие от многих других языков программирования, не требуется явно указывать, что тип реализует интерфейс. Если методы типа соответствуют интерфейсу, то этот тип считается его реализующим:
type MyReader struct{}

func (mr *MyReader) Read(p []byte) (n int, err error) {
// Реализация
return
}

// MyReader неявно реализует интерфейс Reader


3️⃣Использование интерфейсов для абстракции: Интерфейсы можно использовать для создания функций, которые принимают параметры интерфейсного типа, позволяя передавать в них любой объект, который реализует данный интерфейс:
func process(r Reader) {
// функция работает с любым объектом, который удовлетворяет интерфейсу Reader
}


4️⃣Полиморфизм: Интерфейсы обеспечивают полиморфизм, позволяя использовать различные типы, реализующие один и тот же интерфейс, в различных контекстах, где ожидается этот интерфейс.

Допустим, у нас есть интерфейс Shape с методом Area, который должен возвращать площадь фигуры. Мы можем реализовать этот интерфейс в различных структурах:
type Shape interface {
Area() float64
}

type Circle struct {
Radius float64
}

func (c *Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}

type Square struct {
Side float64
}

func (s *Square) Area() float64 {
return s.Side * s.Side
}

func printArea(shape Shape) {
fmt.Println(shape.Area())
}


Теперь функция printArea может принимать любой объект, который реализует интерфейс Shape.

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

👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 349 вопроса на Golang разработчика. Ставь 👍 если нравится контент

🧩 Идущий к IT |👨‍💻 Golang Чат | 🔐 База собесов
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10