2013-11-02 16 views

risposta

5

Ecco un buon esempio da uno degli inventori del Go, Rob Pike, di utilizzare la concorrenza, perché è un modo più semplice per esprimere la soluzione ad un problema:

Lexical Scanning in Go

Generalizzando su quella un po ', qualsiasi problema produttore-consumatore è naturale per 2 goroutine che usano un canale per passare le produzioni dal produttore al consumatore.

Un altro buon utilizzo per la concorrenza è l'interazione con più origini di input/output (dischi, rete, terminale, ecc.). Il tuo programma dovrebbe essere in grado di svegliarsi e fare un po 'di lavoro ogni volta che un risultato proviene da una di queste fonti. È possibile farlo con un thread e una chiamata di sistema come poll (2) o select (2). Quando il thread si attiva, deve capire quale risultato è arrivato, trovare da dove è stato interrotto nell'attività in questione e riprendere da lì. Questo è un sacco di codice che devi scrivere.

Scrivere quel codice è molto più semplice utilizzando una goroutine per attività. Quindi lo stato di quel compito viene catturato implicitamente nella goroutine, e riprendere da dove era stato interrotto è semplice come svegliarsi e correre.

6

non sono un esperto in Go (ancora), ma direi:

Ogni volta è più facile farlo.

La bellezza del modello di concorrenza in Go è che non è fondamentalmente un'architettura multi-core con controlli e equilibri dove le cose solitamente rompono - è un paradigma multi-thread che non solo si adatta bene in un multi-core architettura, si adatta bene anche a un'architettura di sistema distribuita.

Non è necessario creare accordi speciali per più goroutines per lavorare insieme in modo armonioso: basta!

Ecco un esempio di un algoritmo naturalmente concorrente: voglio unire più canali in uno solo. Una volta che tutti i canali di input sono esauriti, voglio chiudere il canale di uscita.

È semplicemente più semplice utilizzare la concorrenza - in realtà non sembra nemmeno concorrenza - sembra quasi procedurale.

/* 
    Multiplex a number of channels into one. 
*/ 
func Mux(channels []chan big.Int) chan big.Int { 
    // Count down as each channel closes. When hits zero - close ch. 
    var wg sync.WaitGroup 
    wg.Add(len(channels)) 
    // The channel to output to. 
    ch := make(chan big.Int, len(channels)) 

    // Make one go per channel. 
    for _, c := range channels { 
     go func(c <-chan big.Int) { 
      // Pump it. 
      for x := range c { 
       ch <- x 
      } 
      // It closed. 
      wg.Done() 
     }(c) 
    } 
    // Close the channel when the pumping is finished. 
    go func() { 
     // Wait for everyone to be done. 
     wg.Wait() 
     // Close. 
     close(ch) 
    }() 
    return ch 
} 

L'unica concessione devo far concorrenza qui è usare un sync.WaitGroup come un contatore per contare concurrent.

Si noti che questo non è puramente il mio lavoro - Ho avuto un grande aiuto con questo here.

0
non

anche un esperto di Go, quindi alcuni dei miei approcci possono essere non canonico, ma qui ci sono alcuni modi che ho trovato utile finora concorrenza:

  • Fare operazioni in attesa di una richiesta di rete , I/O su disco o query del database per terminare
  • Esecuzione di algoritmi di divisione e conquista più rapidamente
  • Poiché le goroutine sono funzioni e le funzioni sono cittadini di prima classe in Go, è possibile passarle come variabili. Questo è conveniente quando il tuo programma ha molti pezzi autonomi. (Ad esempio, sto giocando con la simulazione del sistema di traffico di una città.Ogni veicolo è la propria goroutine e comunicano con intersezioni e altri veicoli utilizzando i canali.Ognuno fa le sue cose.)
  • I/O simultaneo operazioni su dispositivi diversi
  • Utilizzato in concomitanza per eseguire l'algoritmo di Dijkstra su un insieme di punti in un'immagine per disegnare linee di "forbici intelligenti" - una goroutine per punto ha reso questa implementazione notevolmente più veloce.
  • GoConvey utilizza la concorrenza per eseguire test tra pacchetti allo stesso tempo per rispondere più rapidamente alle modifiche durante il debug utilizzando the web UI. (Come bonus intrinseco, questo aggiunge un po 'di pseudo-casualità alla sequenza di test in modo che i risultati del test sono davvero coerenti.)

Concurrency potrebbe essere (leggi: "è a volte, ma non necessariamente sempre") utile quando si hanno operazioni che possono essere eseguite indipendentemente l'una dall'altra ma che altrimenti sarebbero eseguite in sequenza. Anche se queste operazioni dipendono dai dati o da qualche tipo di segnale proveniente da altre goroutine in certi punti, puoi comunicarle tutte con i canali.

Per qualche ispirazione e un'importante distinzione in questi argomenti, e per alcune divertenti immagini gopher, vedere Concurrency is not Parallelism.

1

I miei 2 centesimi ... Se pensi ai canali/goroutine solo nel contesto della concorrenza, ti manca la barca.

Mentre go non è un linguaggio oggetto o un linguaggio strettamente funzionale, consente di prendere le caratteristiche del design da entrambi e applicarle.

Uno dei principi fondamentali del design orientato agli oggetti è la responsabilità singola Principal. L'applicazione di questo principio ti costringe a pensare al design in termini di messaggi, piuttosto che a comportamenti di oggetti complessi. Questi stessi vincoli di progettazione possono essere utilizzati in go, per consentire di iniziare a pensare a "messaggi sui canali" che collegano funzioni a scopo singolo.

Questo è solo un esempio, ma se inizi a pensare in questo modo, ne vedrai molti altri.

Problemi correlati