Sobes.tech
Middle

Peut-on utiliser le même buffer []byte dans plusieurs goroutines?

sobes.tech IA

Réponse de l'IA

Oui, c'est possible, mais il est nécessaire d'assurer la synchronisation d'accès pour éviter les conditions de course.

Les approches les plus courantes :

  1. Mutex (sync.Mutex) :

    import "sync"
    
    var buf []byte
    var mu sync.Mutex
    
    func processBuffer() {
        mu.Lock()
        defer mu.Unlock()
        // Accès sécurisé à buf
        // Par exemple : buf = append(buf, data...)
    }
    
    func main() {
        // Initialisation de buf
        go processBuffer()
        go processBuffer()
        // ...
    }
    
  2. Canaux (chan) :

    On peut transférer la propriété du buffer entre goroutines ou utiliser un canal pour coordonner l'accès.

    import "bytes"
    
    type BufferAccess struct {
        buf *bytes.Buffer // Pointeur vers le buffer pour usage partagé
        mu  sync.Mutex    // Mutex pour la synchronisation
    }
    
    func (ba *BufferAccess) Write(p []byte) (n int, err error) {
        ba.mu.Lock()
        defer ba.mu.Unlock()
        return ba.buf.Write(p)
    }
    
    func worker(ba *BufferAccess, data []byte) {
        ba.Write(data) // Écriture sécurisée via méthode avec mutex
    }
    
    func main() {
        sharedBuffer := &BufferAccess{buf: &bytes.Buffer{}}
        // Lancer des goroutines en passant sharedBuffer
        go worker(sharedBuffer, []byte("hello"))
        go worker(sharedBuffer, []byte("world"))
        // ...
    }
    
  3. Pool de buffers (sync.Pool) :

    Moins besoin de synchronisation pour l'accès au buffer lui-même, si chaque goroutine obtient un buffer du pool, l'utilise, puis le rend.

    import (
        "bytes"
        "sync"
    )
    
    var bufferPool = sync.Pool{
        New: func() interface{} {
            // Taille par défaut du buffer
            return bytes.NewBuffer(make([]byte, 0, 1024))
        },
    }
    
    func processData(data []byte) {
        buf := bufferPool.Get().(*bytes.Buffer)
        defer bufferPool.Put(buf) // Il est crucial de rendre le buffer au pool
    
        buf.Reset() // Nettoyer le buffer avant utilisation
        buf.Write(data)
        // Traitement des données dans le buffer
        // ...
    }
    
    func main() {
        go processData([]byte("message1"))
        go processData([]byte("message2"))
        // ...
    }
    

Important : L'utilisation d'un buffer sans synchronisation dans un environnement concurrent entraînera des conditions de course, ce qui peut conduire à un comportement imprévisible et à des erreurs difficiles à détecter.