Maison > Article > développement back-end > Qu'est-ce que la goroutine en langage Go ?
Goroutine est une implémentation de thread légère dans le langage Go. Il s'agit d'une abstraction légère construite sur des threads et gérée par le runtime Go. Goroutine nous permet d'exécuter plusieurs fonctions ou méthodes en parallèle dans le même espace d'adressage à un coût très faible par rapport aux threads, sa création et sa destruction sont beaucoup moins coûteuses et sa planification est indépendante des threads.
L'environnement d'exploitation de ce tutoriel : système Windows 7, GO version 1.18, ordinateur Dell G3.
Lors de l'écriture d'un programme réseau Socket, vous devez préparer un pool de threads à l'avance pour allouer un thread pour chaque Socket envoyant et recevant des paquets. Les développeurs doivent établir une relation correspondante entre le nombre de threads et le nombre de processeurs pour garantir que chaque tâche peut être allouée au processeur pour un traitement en temps opportun, tout en évitant la perte d'efficacité causée par le changement fréquent de plusieurs tâches entre les threads. .
Bien que le pool de threads fournisse un mécanisme abstrait pour l'allocation de threads pour les rédacteurs logiques. Cependant, face aux exigences de concurrence et de traitement des threads qui peuvent survenir à tout moment et n'importe où, le pool de threads n'est pas très intuitif et pratique. Existe-t-il un mécanisme : si l'utilisateur alloue suffisamment de tâches, le système peut automatiquement aider l'utilisateur à allouer les tâches au processeur afin que ces tâches puissent s'exécuter aussi simultanément que possible. Ce mécanisme est appelé goroutine en langage Go.
goroutine est une implémentation de thread légère dans le langage Go et est gérée par le runtime Go. Les programmes Go alloueront intelligemment les tâches des goroutines à chaque processeur.
Goroutine est une abstraction légère construite sur des threads. Cela nous permet d'exécuter plusieurs fonctions ou méthodes en parallèle dans le même espace d'adressage à un coût très faible. Par rapport aux threads, sa création et sa destruction sont beaucoup moins coûteuses et sa planification est indépendante des threads.
Le programme Go démarre à partir de la fonction main() du package main Lorsque le programme démarre, le programme Go créera une goroutine par défaut pour la fonction main().
Utilisez des fonctions ordinaires pour créer une goroutine
Utilisez le mot-clé go dans le programme Go pour créer une goroutine pour une fonction. Une fonction peut être créée avec plusieurs goroutines, et une goroutine doit correspondre à une fonction.
1) Format
Créer une goroutine pour une fonction commune s'écrit comme suit :
go 函数名( 参数列表 )
Nom de la fonction : le nom de la fonction à appeler.
Liste des paramètres : paramètres qui doivent être transmis lors de l'appel de la fonction.
Lors de l'utilisation du mot-clé go pour créer une goroutine, la valeur de retour de la fonction appelée sera ignorée.
Si vous devez renvoyer des données dans goroutine, veuillez utiliser la fonctionnalité de canal introduite plus tard pour transmettre les données de goroutine comme valeur de retour via le canal.
2) Exemple
Utilisez le mot-clé go pour exécuter la fonction running() simultanément et imprimer le compteur toutes les secondes, pendant que la goroutine principale attend la saisie de l'utilisateur. Les deux actions peuvent être effectuées en même temps. Veuillez vous référer au code ci-dessous :
package main import ( "fmt" "time" ) func running() { var times int // 构建一个无限循环 for { times++ fmt.Println("tick", times) // 延时1秒 time.Sleep(time.Second) } } func main() { // 并发执行程序 go running() // 接受命令行输入, 不做任何事情 var input string fmt.Scanln(&input) }
Le résultat de la ligne de commande est le suivant :
Une fois le code exécuté, la ligne de commande affichera en continu des ticks et vous pourrez utiliser fmt.Scanln() pour accepter les entrées de l'utilisateur. . Les deux étapes peuvent être réalisées simultanément.
La description du code est la suivante :
Ligne 12, utilisez for pour former une boucle infinie.
Ligne 13, la variable times continue d'augmenter dans la boucle.
Ligne 14, affiche la valeur de la variable times.
Ligne 17, utilisez time.Sleep pour faire une pause d'1 seconde puis continuer la boucle.
Ligne 25, utilisez le mot-clé go pour laisser la fonction running() s'exécuter simultanément.
Ligne 29, acceptez la saisie de l'utilisateur jusqu'à ce que la touche Entrée soit enfoncée, le contenu de la saisie est écrit dans la variable d'entrée et revient, et le programme entier se termine.
La séquence d'exécution de ce code est celle indiquée dans la figure ci-dessous.
Figure : Diagramme d'exécution simultanée
Dans cet exemple, lorsque le programme Go démarre, le runtime (runtime) créera par défaut une goroutine pour la fonction main(). Lorsque l'instruction go running est exécutée dans la goroutine de la fonction main(), la goroutine appartenant à la fonction running() est créée et la fonction running() commence à s'exécuter dans sa propre goroutine. À ce stade, main() continue de s'exécuter et les deux goroutines fonctionnent simultanément via le mécanisme de planification du programme Go.
Créer une goroutine à l'aide d'une fonction anonyme
Vous pouvez également démarrer une goroutine pour une fonction anonyme ou une fermeture après le mot-clé go.
1) Le format d'utilisation de fonctions anonymes pour créer des goroutines
Lors de l'utilisation de fonctions anonymes ou de fermetures pour créer des goroutines, en plus d'écrire la partie définition de la fonction après go, vous devez également ajouter les paramètres d'appel de la fonction anonyme , le format est le suivant :
go func( 参数列表 ){ 函数体 }( 调用参数列表 )
Où :
Liste des paramètres : La liste des variables paramètres dans le corps de la fonction.
Corps de fonction : le code de la fonction anonyme.
调用参数列表:启动 goroutine 时,需要向匿名函数传递的调用参数。
2) 使用匿名函数创建goroutine的例子
在 main() 函数中创建一个匿名函数并为匿名函数启动 goroutine。匿名函数没有参数。代码将并行执行定时打印计数的效果。参见下面的代码:
package main import ( "fmt" "time" ) func main() { go func() { var times int for { times++ fmt.Println("tick", times) time.Sleep(time.Second) } }() var input string fmt.Scanln(&input) }
代码说明如下:
第 10 行,go 后面接匿名函数启动 goroutine。
第 12~19 行的逻辑与前面程序的 running() 函数一致。
第 21 行的括号的功能是调用匿名函数的参数列表。由于第 10 行的匿名函数没有参数,因此第 21 行的参数列表也是空的。
扩展知识:Goroutine与线程的区别
许多人认为goroutine比线程运行得更快,这是一个误解。Goroutine并不会更快,它只是增加了更多的并发性。当一个goroutine被阻塞(比如等待IO),golang的scheduler会调度其他可以执行的goroutine运行。与线程相比,它有以下的几个优点:
内存消耗更少:
Goroutine所需要的内存通常只有2kb,而线程则需要1Mb(500倍)
创建与销毁的开销更小:
由于线程创建时需要向操作系统申请资源,并且在销毁时将资源归还,因此它的创建和销毁的开销比较大。相比之下,goroutine的创建和销毁是由go语言在运行时自己管理的,因此开销更低。
切换开销更小:
只是goroutine之于线程的主要区别,也是golang能够实现高并发的主要原因。线程的调度方式是抢占式的,如果一个线程的执行时间超过了分配给它的时间片,就会被其他可执行的线程抢占。在线程切换的过程中需要保存/恢复所有的寄存器信息,比如16个通用寄存器,PC(Program Counter)、SP(Stack Pointer)段寄存器等等。而goroutine的调度是协同式的,它不会直接地与操作系统内核打交道。当goroutine进行切换的时候,之后很少量的寄存器需要保存和恢复(PC和SP)。因此goroutine的切换效率更高。
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!