Для обмена данными между горутинами используются каналы.
Создание каналов, передача значений
В примере ниже показан порядок создания канала, записи данных в него и чтения данных из него:
Отправка значения через канал является синхронной операцией. messages <- "ping"
блокирует выполнение, пока где-то не будет получено значение при помощи <-messages
. Таким образом, каналы позволяют не только обмениваться данными между горутинами, но и синхронизировать их работу.
After sending the message to the channel ➊, goroutine B gets blocked. Only when goroutine A receives the message ➌ does goroutine B continue and print “message sent” ➋.
Закрытие каналов
The writer can close the channel. The reader can detect that the channel is closed.
The writer closes the channel using the close()
function:
The reader checks the channel’s status with a second value (“comma OK”) when reading:
While the channel is open, the reader receives the next value and a true
status. If the channel is closed, the reader gets a zero value ("" for strings) and a false
status.
You can read from a closed channel as much as you want — it always returns a zero value and a false
status.
A channel can only be closed once. Closing it again will cause a panic. You also can’t write to a closed channel.
Here are two important rules:
- Only the writer can close the channel, not the reader. If the reader closes it, the writer will encounter a panic on the next write.
- A writer can only close the channel if they are the sole owner. If there are multiple writers and one closes the channel, the others will face a panic on their next write or attempt to close the channel.
Should I always close a channel?
If you’ve ever worked with external resources (such as files or database connections), you know they should always be closed to prevent leaks. But a channel isn’t an external resource. When a channel is no longer used, Go’s garbage collector will free its resources, whether it’s closed or not.
The only reason to close a channel is to signal to its readers that all data has been sent. If this isn’t important to the readers, then you don’t need to close it.
Итерация по каналу
range
automatically reads the next value from the channel and checks if it’s closed. If the channel is closed, it exits the loop. Note that range over a channel returns a single value, not a pair, unlike range over a slice.
Направленные каналы
Для исключения ошибок, можно указывать направления работы каналов:
chan
(bidirectional): for reading and writing (default);chan<-
(send-only): for writing only;<-chan
(receive-only): for reading only.
The submit()
function needs a send-only channel:
In the function signature ➊, we’ve specified that it’s send-only, so you can’t read from it. Uncomment line ➋, and you’ll get a compile error.
The print()
function needs a receive-only channel:
In the function signature ➊, we’ve specified that it’s receive-only. You can’t write to it. Uncomment lines ➋,➌, and you’ll get a compile error.
You can set the channel direction during initialization, but it’s not very helpful. So, channels are usually initialized for both reading and writing, and specified as directional in function parameters. Go automatically converts a regular channel to a directional one:
Note
Always specify the channel direction in function parameters to avoid runtime errors.
References
- https://antonz.org/go-concurrency/channels/
- Learning Go (Bodner), chapter 10 “Concurrency”
- Язык программирования Go (Донован, Керниган), глава 8.
- https://habr.com/ru/companies/beget/articles/870138/
- http://golangtutorials.blogspot.co.uk/2011/06/channels-in-go.html
- https://appliedgo.net/futures/
📂 Go | Последнее изменение: 02.01.2025 21:33