English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Основной курс Golang

Контрольные операторы в Golang

Функции и методы в Golang

Структуры в Golang

Срезы и массивы в Golang

Строки (String) в Golang

Указатели в Golang

Интерфейсы в Golang

Конкурентное программирование в Golang

Исключения (Error) в Golang

Другие темы Golang

Каналы (Channel) языка Go

В языке Go канал является средством передачи данных между goroutine и позволяет выполнять это без блокировки. Иными словами, канал - это технология, которая позволяет одной goroutine отправлять данные другой goroutine. По умолчанию канал двунаправленный, что означает, что goroutine могут отправлять или принимать данные через один и тот же канал, как показано на следующем рисунке:

Создание канала

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

Синтаксис:

var Channel_name chan Type

Вы также можете использовать краткую запись для создания канала с помощью функции make().

Синтаксис:

channel_name := make(chan Type)
package main
import "fmt"
func main() {
    // Использование ключевого слова var для создания канала
    var mychannel chan int
    fmt.Println("Значение channel:", mychannel)
    fmt.Printf("Тип channel: %T", mychannel)
    // Использование функции make() для создания канала
    mychannel1 := make(chan int)
    fmt.Println("\nЗначение channel1:", mychannel1)
    fmt.Printf("Тип channel1: %T", mychannel1)
}

Вывод:

Значение channel: <nil>
Тип channel: chan int
Значение channel1: 0xc0000160c0
Тип channel1: chan int

Отправка и прием данных через канал

В языке Go работа каналов имеет два основных действия: отправка и接收, которые в совокупности называются коммуникацией. Направление оператора <- указывает на то, идет ли передача данных или их прием. По умолчанию, отправка и прием данных блокируются до тех пор, пока на другом конце канала нет данных. Это позволяет goroutine синхронизироваться друг с другом без использования явных блокировок или переменных условия.

  1. Операция отправки:Операция отправки используется для передачи данных из одного goroutine в другое при помощи канала. Значения, такие как int, float64 и bool, могут быть безопасно и легко отправлены через канал, так как они копируются, и не существует риска случайного параллельного доступа к одному и тому же значению. Также, строки безопасны, так как они не изменяются. Однако, отправка через канал указателей или ссылок (например, массивов, множеств и т.д.) не безопасна, так как значения указателей или ссылок могут изменяться параллельно отправляющим или получающим goroutine, и результат может быть непредсказуемым. Поэтому, при использовании указателей или ссылок в канале, необходимо обеспечить, чтобы они могли быть доступны только одному goroutine за один раз.

    Mychannel <- element

    Указанное выше предложение означает, что данные (element) были отправлены в<-оператор помогает отправлять данные в канал (Mychannel).

  2. операция получения:операция получения используется для получения данных, отправленных отправителем.

    element := <-Mychannel

    Указанное выше предложение означает, что элемент был получен из канала (Mychannel). Если полученное значение не доступно для использования (не нужно использовать), это также является эффективным предложением. Вы также можете написать следующее предложение получения:

    <-Mychannel
package main 
  
import "fmt"
  
func myfunc(ch chan int) { 
  
    fmt.Println(234 + <-ch) 
} 
func main() { 
    fmt.Println("начало метода главного") 
    // создание канала l 
    ch := make(chan int) 
  
    go myfunc(ch) 
    ch <- 23 
    fmt.Println("конец метода главного") 
}

Вывод:

начало метода главного
257
конец метода главного

закрыть канал

Вы также можете закрыть канал с помощью функции close(). Это вbuilt функция, которая устанавливает индикатор, что больше не будут отправляться значения в канал.

Синтаксис:

close()

Вы также можете использовать цикл range для закрытия канала. В данном случае, приемник goroutine может использовать данную грамматику для проверки, открыт канал или закрыт:

ele, ok := <-Mychannel

В данном случае, если значение ok установлено в true, это означает, что канал открыт, поэтому можно выполнить чтение. И если значение установлено в false, это означает, что канал закрыт, поэтому чтение не будет выполняться.

// Объяснение Go программы
// закрытие используемого канала
// цикл range и функция关闭
package main
import "fmt"
func myfun(mychnl chan string) {
    for v := 0; v < 4; v++ {
        mychnl <- "w3codebox"
    }
    close(mychnl)
}
func main() {
    // создание канала
    c := make(chan string)
    // использование Goroutine
    go myfun(c)
    // когда значение ok установлено в true, это означает, что канал открыт, можно отправлять или принимать данные
    // когда значение ok установлено в false, это означает, что канал закрыт
    for {
        res, ok := <-c
        if ok == false {
            fmt.Println("канал закрыт", ok)
            прервать
        }
        fmt.Println("Открытие канала ", res, ok)
    }
}

Вывод:

Открытие канала w3codebox true
Открытие канала w3codebox true
Открытие канала w3codebox true
Открытие канала w3codebox true
Закрытие канала false

Важные注意事项

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

  • Нулевой канал: каналнулевое значение nil.

  • Цикл for в каналах: Цикл for может перебирать значения, отправленные по каналу, до его закрытия.

    Синтаксис:

    for item := range Chnl { 
         // Строка...
    }
    package main 
    import "fmt"
      
    func main() { 
      
        // Использование функции make() для создания канала
        mychnl := make(chan string) 
      
        // Анонимная goroutine 
        go func() { 
            mychnl <- "GFG"
            mychnl <- "gfg"
            mychnl <- "Geeks"
            mychnl <- "w3codebox"
            close(mychnl) 
        } 
      
        // Использование цикла for
        for res := range mychnl { 
            fmt.Println(res) 
        } 
    }

    Вывод:

    GFG
    gfg
    Geeks
    w3codebox
  • Длина канала:В каналах вы можете использоватьФункция len()Найти длину канала. Здесь длина означает количество значений, стоящих в очереди в буфере канала.

    package main 
      
    import "fmt"
    func main() { 
      
        // Использование функции make() для создания канала 
        mychnl := make(chan string, 4) 
        mychnl <- "GFG"
        mychnl <- "gfg"
        mychnl <- "Geeks"
        mychnl <- "w3codebox"
        // Использование функции len() для определения длины канала 
        fmt.Println("Длина канала: ", len(mychnl)) 
    }

    Вывод:

    Длина канала: 4
  • Емкость канала:В каналах вы можете использовать функцию cap() для определения емкости канала. Здесь емкость означает размер буфера.

    package main
    import "fmt"
    func main() {
        // Использование функции make() для создания канала
        mychnl := make(chan string, 4)
        mychnl <- "GFG"
        mychnl <- "gfg"
        mychnl <- "Geeks"
        mychnl <- "w3codebox"
        // Использование функции cap() для определения емкости канала
        fmt.Println("Емкость канала: ", cap(mychnl))
    }

    Вывод:

    Емкость канала: 5
  • Select и оператор case в каналах:В языке Go, оператор select resembles a switch statement without any input parameters. The select statement is used in channels to execute a single operation from multiple operations provided by case blocks.