Как в Go узнать ёмкость (capacity) и текущую длину (length) канала?

Ответ

В Go для работы с размерами канала используются две встроенные функции: cap() для ёмкости и len() для текущего количества элементов.

1. Ёмкость канала — cap()

Функция cap() возвращает ёмкость (capacity) канала, то есть размер его буфера. Это максимальное количество элементов, которое можно отправить в канал без блокировки.

  • Для буферизированных каналов cap() вернет размер буфера, указанный при создании.
  • Для небуферизированных каналов cap() всегда возвращает 0.
// Буферизированный канал
bufChan := make(chan int, 5)
fmt.Println(cap(bufChan)) // Вывод: 5

// Небуферизированный канал
unbufChan := make(chan int)
fmt.Println(cap(unbufChan)) // Вывод: 0

2. Текущее количество элементов — len()

Функция len() возвращает текущее количество элементов, находящихся в буфере канала.

ch := make(chan int, 3)
fmt.Printf("Ёмкость: %d, Длина: %dn", cap(ch), len(ch))

ch <- 1
ch <- 2
fmt.Printf("Ёмкость: %d, Длина: %dn", cap(ch), len(ch))

<-ch
fmt.Printf("Ёмкость: %d, Длина: %dn", cap(ch), len(ch))

// Вывод:
// Ёмкость: 3, Длина: 0
// Ёмкость: 3, Длина: 2
// Ёмкость: 3, Длина: 1

⚠️ Важное замечание: В реальном коде редко полагаются на len() для управления потоком данных в конкурентных программах. Состояние канала может измениться между вызовом len() и следующей операцией. Вместо этого используются блокирующие операции чтения/записи, select или закрытие канала для синхронизации горутин.

Ответ 18+ 🔞

Ах ты ж ёпта, ну и тема у нас сегодня — каналы в Go и как их, блядь, измерить! Сидишь ты такой, пишешь горутины, швыряешь туда-сюда данные, а потом бац — надо понять, сколько в канале места осталось, а сколько уже забито. Ну, хули, Go и тут не подвёл, дал две простые, как три копейки, функции: cap() и len().

1. Ёмкость, сука — cap()

Вот смотри, cap() — это типа твой личный замерщик буфера. Он тебе честно скажет, насколько канал, блядь, растягивается. Создал буферизированный канал на пять мест — cap() вернёт пятёрку, как миленький. А если ты жмот и сделал небуферизированный, ну, тот, что без буфера, — получишь ноль, ебать мои старые костыли! Всё честно.

// Канал с буфером, как порядочный
bufChan := make(chan int, 5)
fmt.Println(cap(bufChan)) // Выведет: 5, ядрёна вошь!

// А это — канал-спринтер, без буфера
unbufChan := make(chan int)
fmt.Println(cap(unbufChan)) // Выведет: 0, хуй с горы, неожиданно?

2. Текущая загрузка — len()

А вот len() — это уже сторож на складе. Он тебе докладывает: «Шеф, у нас вот столько-то ящиков уже лежит!». Отправил два значения — len() подскочил до двух. Забрал одно — упал до одного. Всё логично, пиздец как просто.

ch := make(chan int, 3)
fmt.Printf("Ёмкость: %d, Длина: %dn", cap(ch), len(ch)) // Пусто, блядь!

ch <- 1
ch <- 2
fmt.Printf("Ёмкость: %d, Длина: %dn", cap(ch), len(ch)) // Опа, уже два!

<-ch
fmt.Printf("Ёмкость: %d, Длина: %dn", cap(ch), len(ch)) // Забрали один, остался один.

// Вывод:
// Ёмкость: 3, Длина: 0
// Ёмкость: 3, Длина: 2
// Ёмкость: 3, Длина: 1

⚠️ А теперь, сука, важный момент на посошок! В реальной жизни, в этих ваших конкурентных плясках, на len() полагаться — это как ходить по охуенно тонкому льду. Пока ты смотришь на длину, канал уже может измениться — туда долбанут новое значение или выдернут старое. Поэтому умные дядьки используют не эти замеры, а нормальную синхронизацию: блокирующие операции, select или закрытие каналов. А len() — это так, для справки, чтоб в отладке посмотреть, что творится в этой кухне. Чисто прикинуть, не переполняется ли буфер, пока ты кофе пил.