@ike_lowe
Горутины в Go представляют собой легковесные потоки выполнения, которые могут быть запущены и управляемы в рамках одного процесса. Они позволяют параллельно выполнять несколько функций или методов.
Горутины используют механизмы синхронизации для избежания гонок данных, которые могут возникнуть при обращении к общим ресурсам из нескольких горутин одновременно.
Одним из основных механизмов синхронизации в Go является канал (channel). Каналы предоставляют способ передачи данных между горутинами без необходимости использования явных блокировок или мьютексов.
Каналы могут быть созданы с помощью функции make
, например:
1
|
ch := make(chan int) |
Для отправки данных по каналу используется оператор <-
. Например, чтобы отправить число 42 по каналу ch
, нужно написать:
1
|
ch <- 42 |
Для получения данных из канала также используется оператор <-
. Например, чтобы получить число из канала ch
и сохранить его в переменной x
, нужно написать:
1
|
x := <-ch |
Оператор <-
блокирует горутину до тех пор, пока значение не будет передано или прочитано из канала.
Каналы могут использоваться для синхронизации выполнения горутин. Например, можно создать канал, отправить значение в него из одной горутины, а затем в другой горутине получить это значение. Таким образом, горутины можно синхронизировать и гарантировать, что определенный блок кода будет выполняться после завершения другого блока кода.
Еще одним механизмом синхронизации в Go являются мьютексы (mutex). Мьютексы позволяют защитить доступ к общему ресурсу и гарантировать, что только одна горутина будет исполнять код, защищенный мьютексом, в определенный момент времени. Мьютексы реализуются с помощью структуры sync.Mutex
и методов Lock
и Unlock
.
Пример использования мьютекса:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
var mutex sync.Mutex var x int // Горутина 1 go func() { mutex.Lock() defer mutex.Unlock() x = 42 }() // Горутина 2 go func() { mutex.Lock() defer mutex.Unlock() fmt.Println(x) // Вывод: 42 }() |
В данном примере обе горутины сначала блокируют мьютекс, затем выполняют код, защищенный мьютексом, и, наконец, разблокируют мьютекс с помощью оператора defer
. Это гарантирует, что горутины выполнят код в нужной последовательности и избегут гонок данных.