ПрограммированиеMiddle Backend Go разработчик

Что происходит при передаче значений по каналу в Go: как устроено копирование, какие типы передаются по значению, как можно случайно получить race при передаче сложных структур или указателей?

Проходите собеседования с ИИ помощником Hintsage

Ответ

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

  • Передача «по значению»: стандартные типы и структуры (без указателей) копируются, получатель получает свою копию, и изменения не влияют на оригинал.
  • Проверка race: если по каналу передан указатель, обе стороны (отправитель и получатель) работают c одной и той же областью памяти — возможен data race!
  • Сложные структуры с вложенными указателями: даже если основная структура передаётся по значению, вложенные в неё указатели копируются как ссылки, и race возможен на уровне вложенных объектов.

Код и пример:

type Data struct { N int } c := make(chan Data) d := Data{N: 1} c <- d // копируется структура целиком p := &Data{N: 3} c2 := make(chan *Data) c2 <- p // по каналу ушёл указатель на тот же самый объект

Вопрос с подвохом

Если по каналу передать структуру, содержащую поле-указатель — будет ли race condition при изменении этого поля с обеих концов канала?

Ответ:

  • Race возможен! Структура копируется, но вложенный указатель ссылается на одну и ту же область памяти. Если обе стороны модифицируют данные по ссылке, возникает состояние гонки.

Пример:

type Box struct { Ptr *int } x := 10 chanBox := make(chan Box) chanBox <- Box{Ptr: &x} // и отправитель, и получатель имеют доступ к x!

Примеры реальных ошибок из-за незнания тонкостей темы


История

В распределённой очереди были частые "случайные" падения и загадочные значения в структуре задачи. Оказалось, по каналу гоняли указатели на общие структуры, которые параллельно изменялись в нескольких горутинах. Решили переводом передачи на копии данных.


История

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


История

В сервисе пуш-уведомлений через канал передавались ссылки на объекты, которые потом обрабатывались горутинами. При одновременном завершении работы и закрытии канала часть структур еще модифицировались, вызывая панику или data race. Помог переход к копированию структуры перед отправкой.