← Назад ко всем вопросам

Что происходит при записи в канал из двух горутин одновременно

1️⃣ Как кратко ответить

При записи в канал из двух горутин одновременно, одна из горутин успешно записывает данные в канал, если в нем есть свободное место, а другая блокируется до тех пор, пока место не освободится. Если канал буферизирован, запись происходит в порядке поступления данных, если нет — горутина блокируется до тех пор, пока другая горутина не прочитает данные из канала.

2️⃣ Подробное объяснение темы

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

Небуферизированные каналы

Небуферизированный канал не имеет внутреннего буфера для хранения данных. Это означает, что запись в такой канал блокируется до тех пор, пока другая горутина не прочитает данные из канала. Если две горутины пытаются записать в небуферизированный канал одновременно, одна из них будет заблокирована до тех пор, пока другая горутина не прочитает данные.

Пример:

package main
​
import (
	"fmt"
	"time"
)
​
func main() {
	ch := make(chan int)
​
	go func() {
		ch <- 1 // Эта горутина блокируется, пока main не прочитает данные
		fmt.Println("Горутина 1 записала 1")
	}()
​
	go func() {
		ch <- 2 // Эта горутина блокируется, пока main не прочитает данные
		fmt.Println("Горутина 2 записала 2")
	}()
​
	time.Sleep(time.Second)
	fmt.Println(<-ch) // Чтение из канала разблокирует одну из горутин
	fmt.Println(<-ch) // Чтение из канала разблокирует вторую горутину
}

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

Буферизированные каналы

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

Пример:

package main
​
import (
	"fmt"
	"time"
)
​
func main() {
	ch := make(chan int, 2) // Создаем буферизированный канал с размером буфера 2
​
	go func() {
		ch <- 1 // Запись в канал, не блокируется, так как есть место в буфере
		fmt.Println("Горутина 1 записала 1")
	}()
​
	go func() {
		ch <- 2 // Запись в канал, не блокируется, так как есть место в буфере
		fmt.Println("Горутина 2 записала 2")
	}()
​
	time.Sleep(time.Second)
	fmt.Println(<-ch) // Чтение из канала
	fmt.Println(<-ch) // Чтение из канала
}

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

Заключение

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

Тема: Конкурентность
Стадия: Tech

🔒 Подпишись на бусти автора и стань Алигатором, чтобы получить полный доступ к функционалу сайта и отслеживать свой прогресс!

Твои заметки