Конкурентность в Go – это особенность языка программирования, которая позволяет создавать масштабируемые и эффективные приложения. Она основана на использовании горутин, каналов и других механизмов синхронизации.
Горутины – это легковесные потоки выполнения, которые могут быть запущены параллельно друг другу. Они используются для выполнения задач, которые не зависят друг от друга и могут быть выполнены параллельно. Горутины создаются с помощью ключевого слова go и могут быть переданы параметры.
Пример создания горутины:
func main() {
go printNumbers()
}
func printNumbers() {
for i := 0; i < 10; i++ {
fmt.Println(i)
}
}
В этом примере мы создаем горутину, которая будет выводить числа от 0 до 9. Главная функция main продолжит свое выполнение, не ожидая завершения горутины.
Каналы – это механизм обмена данными между горутинами. Они позволяют передавать значения между горутинами без необходимости использования блокировок или мьютексов. Каналы могут быть созданы с помощью функции make и переданы в качестве параметров функций.
Пример создания канала:
ch := make(chan int)
В этом примере мы создаем канал, который будет передавать значения типа int.
Каналы могут быть использованы для синхронизации выполнения горутин. Например, мы можем создать две горутины, одна из которых будет отправлять значения в канал, а другая – получать их.
Пример использования канала:
func main() {
ch := make(chan int)
go sendNumbers(ch)
receiveNumbers(ch)
}
func sendNumbers(ch chan int) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
}
func receiveNumbers(ch chan int) {
for number := range ch {
fmt.Println(number)
}
}
В этом примере мы создаем канал и две горутины. Горутина sendNumbers отправляет значения в канал, а горутина receiveNumbers получает их и выводит на экран. Функция close используется для закрытия канала после того, как все значения были отправлены.
Подробней о каналах и горутинах:
Select – это конструкция языка, которая позволяет выбирать из нескольких операций чтения или записи в канал. Она используется для ожидания событий от нескольких каналов одновременно.
Пример использования select:
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go sendNumbers(ch1)
go sendNumbers(ch2)
for i := 0; i < 20; i++ {
select {
case number := <-ch1:
fmt.Println("ch1:", number)
case number := <-ch2:
fmt.Println("ch2:", number)
}
}
}
func sendNumbers(ch chan int) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
}
В этом примере мы создаем два канала и две горутины, которые отправляют значения в эти каналы. Затем мы используем конструкцию select для выбора из двух каналов одновременно.
Mutex – это механизм синхронизации доступа к общим данным. Он используется для предотвращения состояния гонки, когда несколько горутин пытаются изменить одни и те же данные одновременно.
Пример использования mutex:
import "sync"
var counter int
var mutex sync.Mutex
func main() {
for i := 0; i < 10; i++ {
go incrementCounter()
}
}
func incrementCounter() {
mutex.Lock()
defer mutex.Unlock()
counter++
fmt.Println(counter)
}
В этом примере мы создаем 10 горутин, которые пытаются увеличить значение переменной counter. Мы используем mutex для блокировки доступа к переменной counter во время ее изменения.
Конкурентность в Go позволяет создавать эффективные и масштабируемые приложения. Она основана на использовании горутин, каналов, select и mutex. Горутины позволяют выполнять задачи параллельно, каналы – передавать данные между горутинами, select – ожидать событий от нескольких каналов одновременно, а mutex – синхронизировать доступ к общим данным.