Maison > développement back-end > Golang > Partage de conseils pratiques pour la programmation concurrente en Golang : faire jouer pleinement les avantages des Goroutines

Partage de conseils pratiques pour la programmation concurrente en Golang : faire jouer pleinement les avantages des Goroutines

PHPz
Libérer: 2023-07-19 12:43:48
original
877 Les gens l'ont consulté

Partage de conseils pratiques pour la programmation simultanée en Golang : exploitez pleinement les avantages de Goroutines

En langage Go, Goroutines est une implémentation de thread légère, ce qui rend la programmation simultanée très simple et efficace. En tirant pleinement parti des avantages des Goroutines, nous pouvons mieux utiliser les processeurs multicœurs et améliorer les performances et le débit des programmes. Cet article partagera quelques conseils pratiques pour vous aider à mieux utiliser Goroutines pour la programmation simultanée.

1. Solutions aux problèmes de concurrence

En programmation simultanée, le problème le plus courant est l'accès simultané aux ressources partagées. Pour résoudre ce problème, nous pouvons utiliser un mutex ou un canal pour protéger l'accès aux ressources partagées.

  1. Verrouillage Mutex

Le verrouillage Mutex peut garantir qu'un seul Goroutine peut accéder aux ressources partagées en même temps, et que les autres Goroutines doivent attendre que le verrou soit libéré avant de pouvoir y accéder. Voici un exemple de code simple :

package main

import (
    "fmt"
    "sync"
)

var (
    counter int
    mutex   sync.Mutex
    wg      sync.WaitGroup
)

func main() {
    wg.Add(2)
    go increment(1)
    go increment(2)
    wg.Wait()
    fmt.Println("counter:", counter)
}

func increment(id int) {
    defer wg.Done()

    for i := 0; i < 100000; i++ {
        mutex.Lock()
        counter++
        mutex.Unlock()
    }
}
Copier après la connexion

Dans le code ci-dessus, nous utilisons sync.Mutex pour créer un verrou mutex. Dans la fonction increment, avant chaque modification de la ressource partagée counter, on appelle d'abord la méthode Lock pour verrouiller le mutex, puis on appelle < La méthode code>Déverrouiller se déverrouille. Cela garantit qu'un seul Goroutine modifie le counter en même temps. sync.Mutex来创建了一个互斥锁。在increment函数中,每次对共享资源counter进行修改之前,我们先调用Lock方法锁定互斥锁,然后再调用Unlock方法解锁。这样可以保证同时只有一个Goroutine在修改counter

  1. 通道

通道是一种可以用于在Goroutines之间进行通信的数据结构,它可以实现同步和传递数据。通过通道,我们可以安全地共享资源的访问,避免竞态条件。

下面是一个使用通道的示例代码:

package main

import (
    "fmt"
    "sync"
)

var (
    counter int
    wg      sync.WaitGroup
)

func main() {
    ch := make(chan int)
    wg.Add(2)
    go increment(1, ch)
    go increment(2, ch)
    wg.Wait()
    close(ch)
    
    for count := range ch {
        counter += count
    }
    
    fmt.Println("counter:", counter)
}

func increment(id int, ch chan int) {
    defer wg.Done()

    for i := 0; i < 100000; i++ {
        ch <- 1
    }
}
Copier après la connexion

在上面的代码中,我们创建了一个有缓冲的通道ch,通过通道传递整数值1。在increment函数中,我们在每次迭代中,将一个1发送到通道ch中。在main函数中,我们使用range来从通道中接收整数值,然后累加到counter中。

二、避免Goroutine泄漏

在并发编程中,Goroutine泄漏是一种常见的问题。如果Goroutine创建后没有得到正确地关闭,会导致资源的浪费和性能的下降。

为了避免Goroutine泄漏,我们可以使用context包来进行协程控制和取消。下面是示例代码:

package main

import (
    "context"
    "fmt"
    "sync"
    "time"
)

var wg sync.WaitGroup

func main() {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)

    wg.Add(1)
    go worker(ctx)

    time.Sleep(3 * time.Second)
    cancel()

    wg.Wait()
    fmt.Println("main function exit")
}

func worker(ctx context.Context) {
    defer wg.Done()

    for {
        select {
        case <-ctx.Done():
            fmt.Println("worker cancelled")
            return
        default:
            fmt.Println("worker is running")
        }

        time.Sleep(1 * time.Second)
    }
}
Copier après la connexion

在上面的代码中,我们使用context.Backgroundcontext.WithCancel创建了一个带有取消功能的上下文。在main函数中,我们启动了一个Goroutine来执行worker函数,并传递了上下文。在worker函数中,我们通过不断监听上下文的取消信号来判断是否需要退出。一旦收到取消信号,我们就关闭Goroutine,并输出相应的日志。

通过使用context包,我们可以更好地控制Goroutine的生命周期和资源的释放,避免了Goroutine泄漏。

三、并行执行任务

在实际的应用中,我们经常需要并行执行多个任务,然后等待所有任务完成后再进行下一步操作。这时,我们可以使用sync.WaitGroupchannel来实现。

下面是一个并行执行任务的示例代码:

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

func main() {
    tasks := make(chan int, 10)
    wg.Add(3)

    go worker(1, tasks)
    go worker(2, tasks)
    go worker(3, tasks)

    for i := 0; i < 10; i++ {
        tasks <- i
    }

    close(tasks)
    wg.Wait()
    fmt.Println("all tasks done")
}

func worker(id int, tasks chan int) {
    defer wg.Done()

    for task := range tasks {
        fmt.Printf("worker %d: processing task %d
", id, task)
    }
}
Copier après la connexion

在上面的代码中,我们创建了一个缓冲为10的通道tasks,然后启动了3个Goroutine来执行worker函数。在main函数中,我们通过循环将10个任务发送到通道中,然后关闭通道。在worker函数中,我们从通道中取出任务,并输出相应的日志。

通过并行执行任务,我们可以充分利用多核处理器,加快程序的执行速度。

总结

通过充分发挥Goroutines的优势,我们可以更好地进行并发编程。在解决共享资源并发访问问题时,我们可以使用互斥锁或通道来保护共享资源的访问。同时,我们也需要注意避免Goroutine泄漏,合理控制Goroutine的生命周期和资源的释放。在需要并行执行任务时,我们可以使用sync.WaitGroupchannel

    Channel

    🎜Un canal est une structure de données qui peut être utilisée pour communiquer entre Goroutines, qui peuvent réaliser la synchronisation et transférer des données. Grâce aux canaux, nous pouvons partager l’accès aux ressources en toute sécurité et éviter les conditions de concurrence. 🎜🎜Voici un exemple de code utilisant un canal : 🎜rrreee🎜Dans le code ci-dessus, nous créons un canal tamponné ch et transmettons la valeur entière 1 via le canal. Dans la fonction increment, on envoie un 1 au canal ch à chaque itération. Dans la fonction main, nous utilisons range pour recevoir la valeur entière du canal, puis l'accumulons dans le compteur. 🎜🎜2. Évitez les fuites Goroutine🎜🎜En programmation simultanée, les fuites Goroutine sont un problème courant. Si Goroutine n'est pas fermé correctement après la création, cela entraînera un gaspillage de ressources et une dégradation des performances. 🎜🎜Afin d'éviter les fuites de Goroutine, nous pouvons utiliser le package context pour le contrôle et l'annulation de la coroutine. Voici l'exemple de code : 🎜rrreee🎜Dans le code ci-dessus, nous avons créé un contexte avec une fonctionnalité d'annulation en utilisant context.Background et context.WithCancel. Dans la fonction main, nous démarrons une Goroutine pour exécuter la fonction worker et transmettre le contexte. Dans la fonction worker, nous surveillons constamment le signal d'annulation du contexte pour déterminer si nous devons quitter. Une fois le signal d'annulation reçu, nous fermons le Goroutine et générons le journal correspondant. 🎜🎜En utilisant le package context, nous pouvons mieux contrôler le cycle de vie de Goroutine et la libération des ressources, évitant ainsi les fuites de Goroutine. 🎜🎜3. Exécuter des tâches en parallèle🎜🎜Dans les applications réelles, nous devons souvent exécuter plusieurs tâches en parallèle, puis attendre que toutes les tâches soient terminées avant de passer à l'étape suivante. Pour le moment, nous pouvons utiliser sync.WaitGroup et channel pour y parvenir. 🎜🎜Ce qui suit est un exemple de code pour exécuter des tâches en parallèle : 🎜rrreee🎜Dans le code ci-dessus, nous créons un canal tâches avec un tampon de 10, puis démarrons 3 Goroutines pour exécuter fonction travailleur. Dans la fonction main, nous envoyons 10 tâches dans le canal via une boucle, puis fermons le canal. Dans la fonction worker, nous supprimons les tâches du canal et générons les journaux correspondants. 🎜🎜En exécutant des tâches en parallèle, nous pouvons exploiter pleinement les processeurs multicœurs et accélérer l'exécution des programmes. 🎜🎜Résumé🎜🎜En tirant pleinement parti des avantages des Goroutines, nous pouvons mieux effectuer la programmation simultanée. Lors de la résolution du problème de l'accès simultané aux ressources partagées, nous pouvons utiliser des mutex ou des canaux pour protéger l'accès aux ressources partagées. Dans le même temps, nous devons également faire attention à éviter les fuites de Goroutine et contrôler raisonnablement le cycle de vie de Goroutine et la libération des ressources. Lorsque nous devons exécuter des tâches en parallèle, nous pouvons utiliser sync.WaitGroup et channel pour y parvenir. 🎜🎜En utilisant correctement ces techniques, nous pouvons améliorer les performances et le débit du programme tout en garantissant l'exactitude et la stabilité du programme. J'espère que cet article vous sera utile lorsque vous utiliserez Goroutines pour la programmation simultanée. 🎜

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal