ProgrammazioneSviluppatore Backend Go di livello medio

Что происходит при передаче значений по каналу в Go: как устроено копирование, какие типы передаются по значению, как можно случайно получить race при передаче сложных структур или указателей?

Supera i colloqui con l'assistente IA Hintsage

Risposta

In Go è possibile inviare attraverso i canali valori di qualsiasi tipo: int, struct, puntatori, interfacce, ecc.

  • Trasmissione «per valore»: i tipi standard e le strutture (senza puntatori) vengono copiati, il destinatario riceve la propria copia e le modifiche non influenzano l'originale.
  • Controllo race: se viene passato un puntatore attraverso il canale, entrambe le parti (mittente e destinatario) lavorano sulla stessa area di memoria — è possibile una race condition!
  • Strutture complesse con puntatori annidati: anche se la struttura principale viene trasmessa per valore, i puntatori annidati vengono copiati come riferimenti, e la race condition è possibile a livello di oggetti annidati.

Codice e esempio:

type Data struct { N int } c := make(chan Data) d := Data{N: 1} c <- d // struttura copiata interamente p := &Data{N: 3} c2 := make(chan *Data) c2 <- p // inviato attraverso il canale un puntatore allo stesso oggetto

Domanda curiosa

Se attraverso il canale viene passata una struttura che contiene un campo-puntatore — ci sarà condizione di race durante la modifica di questo campo da entrambe le estremità del canale?

Risposta:

  • È possibile che si verifichi una race! La struttura viene copiata, ma il puntatore annidato si riferisce alla stessa area di memoria. Se entrambe le parti modificano i dati tramite il riferimento, si verifica una condizione di gara.

Esempio:

type Box struct { Ptr *int } x := 10 chanBox := make(chan Box) chanBox <- Box{Ptr: &x} // sia il mittente che il destinatario hanno accesso a x!

Esempi di errori reali a causa della mancanza di conoscenza dei dettagli della questione


Storia

Nella coda distribuita ci sono stati frequenti “casuali” crash e valori misteriosi nella struttura del compito. Si è scoperto che venivano inviati puntatori a strutture condivise che venivano modificate contemporaneamente in più goroutine. Si è deciso di passare alle copie dei dati.


Storia

L'elaborazione asincrona dei messaggi lavorava con strutture che contenevano slice-puntatori a un array comune. Durante la trasmissione parallela, parti della stessa memoria venivano modificate da diverse posizioni, portando a bug misteriosi e corruzione dei dati.


Storia

Nel servizio di notifiche push venivano passati riferimenti a oggetti, che venivano poi elaborati da goroutine. Durante la chiusura simultanea del lavoro e del canale, alcune strutture venivano ancora modificate, causando panico o race condition. Si è risolto passando alla copia della struttura prima dell'invio.