Maison  >  Article  >  développement back-end  >  Techniques de traitement de canal asynchrone en langage Go

Techniques de traitement de canal asynchrone en langage Go

WBOY
WBOYoriginal
2023-06-03 15:31:341330parcourir

Le canal asynchrone (channel) est l'une des fonctionnalités très importantes du langage Go. Il nous permet de communiquer et de synchroniser entre les goroutines. Cette méthode de communication est très efficace et plus sûre que la mémoire partagée car les opérations de lecture/écriture sur la mémoire partagée nécessitent un verrouillage explicite pour éviter les conditions de concurrence. Dans cet article, nous aborderons certaines techniques courantes utilisées dans la gestion des canaux asynchrones.

  1. Canal tamponné

Un canal tamponné est un canal asynchrone qui peut tamponner un certain temps entre les opérations d'envoi et de réception d'un certain nombre d'éléments. afin que l'expéditeur n'ait pas à attendre le destinataire. En d’autres termes, les canaux mis en mémoire tampon permettent aux coroutines de communiquer de manière asynchrone.

Par exemple, voici un exemple utilisant un canal tamponné :

package main

import "fmt"

func main() {
    ch := make(chan int, 2) // 创建缓冲信道,缓存两个元素
    ch <- 1
    ch <- 2
    fmt.Println(<-ch) // 从信道中读取第一个元素
    fmt.Println(<-ch) // 从信道中读取第二个元素
}

La sortie est :

1
2

Dans l'exemple ci-dessus, nous avons créé A canal tampon ch qui met en cache deux éléments entiers. Ensuite, nous utilisons les instructions ch <- 1 et ch <- 2 pour envoyer les deux éléments au canal. Enfin, nous lisons deux fois les deux éléments du canal en utilisant <-ch. ch,缓存两个整数元素。然后我们使用 ch <- 1ch <- 2两个语句将两个元素发送到信道中去。最后,我们使用<-ch两次从信道中读取这两个元素。

需要注意的是,如果我们尝试往一个已经满了的缓冲信道里发送元素,那么发送操作就会阻塞,直到信道中有空闲位置为止。类似地,如果我们尝试从一个空的缓冲信道中读取元素,那么读取操作也将阻塞,直到信道中有元素为止。

  1. 关闭信道

在使用异步信道时,我们必须注意一些细节。例如,当我们从一个已经关闭的信道里读取数据时,会发生什么呢?

当我们尝试从一个已经关闭的信道中读取数据时,这个读取操作将不再阻塞,而是立即返回一个零值。例如,在下面的示例中我们可以看到当我们从一个已经关闭的信道中读取元素时,将会返回类型的零值:

package main

import "fmt"

func main() {
    ch := make(chan int)
    close(ch)     // 关闭信道
    x, ok := <-ch // 读取信道
    fmt.Println(x, ok) // 输出:0 false
}

需要注意的是,需要在确保有多个协程使用信道时才去关闭它。如果只有一个协程在使用信道,那么我们就不需要去手动关闭信道,因为这样可能会导致其他协程在尝试从发送到这个信道上的数据时引发 panic。

  1. 信道的超时机制

有些情况下,我们在等待一个信道的数据时可能会遇到超时问题。例如,当我们从一个网络连接中读取数据时,如果数据的到来时间超过了我们设定的等待时间,这时我们就需要关闭这个连接,以便让其他的协程可以使用这个资源。

在异步信道处理中,我们可以使用select语句自定义超时机制。下面是一个使用 select语句实现信道超时机制的示例:

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)
    go func() {
        time.Sleep(5 * time.Second)
        ch <- 1
    }()
    select {
    case x := <-ch:
        fmt.Println(x)
    case <-time.After(3 * time.Second):
        fmt.Println("timeout!")
    }
}

在上面的示例中,我们使用time.After()函数返回一个time.Timer类型的实例来等待超时。如果信道在超时之前接收到数据,我们就可以从x := <-ch语句得到数据。否则,当超时发生时,<-time.After(3 * time.Second)语句就会立即执行,并输出一个超时相关的信息。

需要注意的是,在使用信道超时机制时,我们也应该注意关闭了哪个信道,以避免在等待信道接收数据时引发 panic。

  1. select 语句

select语句是 Go 语言中的一个非常重要的语言结构,它可以让我们同时等待多个通信操作。当多个通信操作都准备好了,select语句会随机选择一个语句执行。

下面是一个使用select语句的示例,其中我们同时等待一个信道发送和接收操作:

package main

import (
    "fmt"
)

func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)
    go func() {
        ch1 <- 1
    }()
    select {
    case x := <-ch1:
        fmt.Println(x)
    case ch2 <- 2:
        fmt.Println("send 2")
    }
}

在上面的示例中,我们使用go语句在一个新协程中执行ch1 <- 1语句。然后,我们使用select语句同时等待信道ch1ch2。如果ch1中有元素,我们就可以从x:= <-ch1这个语句中取出它,并将它打印出来。另一方面,如果ch2可以发送元素,那么执行ch2 <- 2并打印输出。

需要注意的是,在使用select语句时,我们不必一定要对所有信道进行接收和发送操作。例如,在上面的示例中我们只对ch1进行了接收操作,而对ch2只进行了发送操作。

总结:

在Go语言中,异步信道处理是一种非常重要的技术。在异步编程时,我们可以使用缓冲信道、关闭信道、超时信道等方式,充分利用信道的高效通信特性。同时,我们也要注意一些技巧,如只关闭正在被多个协程使用的信道、使用select

Il est à noter que si l'on essaie d'envoyer des éléments vers un canal tampon déjà plein, l'opération d'envoi se bloquera jusqu'à ce qu'il y ait un espace libre dans le canal. De même, si nous essayons de lire un élément à partir d'un canal tampon vide, l'opération de lecture se bloquera également jusqu'à ce qu'il y ait un élément dans le canal. #🎜🎜#
    #🎜🎜#Fermer la chaîne#🎜🎜##🎜🎜##🎜🎜#Lors de l'utilisation de chaînes asynchrones, nous devons faire attention à certains détails. Par exemple, que se passe-t-il lorsque nous lisons des données provenant d’un canal fermé ? #🎜🎜##🎜🎜#Lorsque nous essayons de lire des données à partir d'un canal fermé, l'opération de lecture ne bloquera plus, mais renverra immédiatement une valeur nulle. Par exemple, dans l'exemple suivant, nous pouvons voir que lorsque nous lisons un élément d'un canal fermé, une valeur nulle de type sera renvoyée : #🎜🎜#rrreee#🎜🎜#Il est à noter que nous devons nous assurer que Only fermez le canal lorsque plusieurs coroutines l'utilisent. Si une seule coroutine utilise le canal, nous n'avons pas besoin de fermer manuellement le canal, car cela peut provoquer la panique d'autres coroutines lorsqu'elles tentent d'envoyer des données à ce canal. #🎜🎜#
      #🎜🎜#Mécanisme de délai d'expiration du canal#🎜🎜##🎜🎜##🎜🎜#Dans certains cas, nous pouvons rencontrer des problèmes de délai d'attente lors de l'attente des données d'un canal. Par exemple, lorsque nous lisons des données à partir d'une connexion réseau, si l'heure d'arrivée des données dépasse le temps d'attente que nous avons défini, nous devons alors fermer la connexion afin que d'autres coroutines puissent utiliser cette ressource. #🎜🎜##🎜🎜#Dans le traitement de canal asynchrone, nous pouvons utiliser l'instruction select pour personnaliser le mécanisme de délai d'attente. Voici un exemple d'utilisation de l'instruction select pour implémenter le mécanisme de délai d'attente du canal : #🎜🎜#rrreee#🎜🎜#Dans l'exemple ci-dessus, nous utilisons time.After() Renvoie une instance de type <code>time.Timer pour attendre l'expiration du délai. Si le canal reçoit des données avant l'expiration du délai, nous pouvons obtenir les données à partir de l'instruction x := <-ch. Sinon, lorsqu'un délai d'attente se produit, l'instruction <-time.After(3 * time.Second) sera exécutée immédiatement et des informations relatives au délai d'attente seront affichées. #🎜🎜##🎜🎜#Il convient de noter que lors de l'utilisation du mécanisme de délai d'attente du canal, nous devons également faire attention au canal qui est fermé pour éviter la panique en attendant que le canal reçoive des données. #🎜🎜#
        #🎜🎜#select déclaration #🎜🎜##🎜🎜##🎜🎜#select est une structure de langage très importante dans le langage Go, qui nous permet d'attendre plusieurs opérations de communication en même temps. Lorsque plusieurs opérations de communication sont prêtes, l'instruction select sélectionne au hasard une instruction à exécuter. #🎜🎜##🎜🎜#Voici un exemple utilisant l'instruction select, où nous attendons simultanément les opérations d'envoi et de réception d'un canal : #🎜🎜#rrreee#🎜🎜#Dans l'exemple ci-dessus, Nous utilisons l'instruction go pour exécuter l'instruction ch1 <- 1 dans une nouvelle coroutine. Ensuite, nous utilisons l'instruction select pour attendre les canaux ch1 et ch2 simultanément. S'il y a un élément dans ch1, nous pouvons le prendre dans l'instruction x:= <-ch1 et l'imprimer. D'un autre côté, si ch2 peut envoyer des éléments, alors exécutez ch2 <- 2 et imprimez la sortie. #🎜🎜##🎜🎜#Il convient de noter que lors de l'utilisation de l'instruction select, nous n'avons pas besoin d'effectuer des opérations de réception et d'envoi sur tous les canaux. Par exemple, dans l'exemple ci-dessus, nous avons uniquement effectué l'opération de réception sur ch1 et effectué uniquement l'opération d'envoi sur ch2. #🎜🎜##🎜🎜#Résumé : #🎜🎜##🎜🎜#En langage Go, le traitement asynchrone des canaux est une technologie très importante. Dans la programmation asynchrone, nous pouvons utiliser des canaux tampons, des canaux fermés, des canaux timeout, etc. pour exploiter pleinement les caractéristiques de communication efficaces du canal. Dans le même temps, nous devons également prêter attention à certaines techniques, telles que la fermeture uniquement des canaux utilisés par plusieurs coroutines, l'utilisation d'instructions select, etc. Bien entendu, seules quelques techniques courantes sont présentées ici. Des techniques de traitement de canal plus asynchrones doivent être apprises et explorées par nous-mêmes. #🎜🎜#

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn