2015-06-10 43 views
6

Mi trovo spesso ad usare i canali per far smettere le cose. In questi casi il canale viene utilizzato esclusivamente come mezzo di segnalazione e nessuno dei dati viene effettivamente utilizzato.Quale tipo di canale utilizza la quantità minima di memoria in Go?

Ad esempio:

package main 

import (
    "fmt" 
    "time" 
) 

func routine(stopChan chan bool) { 
    fmt.Println("goroutine: I've started!") 
    <-stopChan 
    fmt.Println("goroutine: Cya'round pal") 
} 

func main() { 
    fmt.Println("main: Sample program run started") 

    stopChan := make(chan bool) 

    go routine(stopChan) 

    fmt.Println("main: Fired up the goroutine") 

    stopChan <- true 

    time.Sleep(1 * time.Second) 

    fmt.Println("main: Sample program run finished") 
} 

// Sample output: 
// 
// main: Sample program run started 
// main: Fired up the goroutine 
// goroutine: I've started! 
// goroutine: Cya'round pal 
// main: Sample program run finished 

Run/view it se vi piace al parco giochi golang.


La mia domanda è:

Quale tipo di canale ha il più leggero ingombro di memoria in Go?

ad es. Un bool chan richiederà un overhead minore rispetto a una struct vuota {} chan?

chan bool

chan byte

chan interface{}

chan struct{}

...

qualcos'altro?

+2

Non ho verificato nella sorgente, ma mi aspetto che il sovraccarico del canale stesso domini l'effetto di byte, bool o struct {} per un canale non bufferizzato. – Volker

risposta

6

Guardando il latest implementation del canale, non è una struttura banale:

type hchan struct { 
    qcount uint   // total data in the queue 
    dataqsiz uint   // size of the circular queue 
    buf  unsafe.Pointer // points to an array of dataqsiz elements 
    elemsize uint16 
    closed uint32 
    elemtype *_type // element type 
    sendx uint // send index 
    recvx uint // receive index 
    recvq waitq // list of recv waiters 
    sendq waitq // list of send waiters 
    lock  mutex 
} 

Elementi di code cameriere sono anche quite heavy:

type sudog struct { 
    g   *g 
    selectdone *uint32 
    next  *sudog 
    prev  *sudog 
    elem  unsafe.Pointer // data element 
    releasetime int64 
    nrelease int32 // -1 for acquire 
    waitlink *sudog // g.waiting list 
} 

Vedete, molti byte. Anche se qualsiasi elemento sarebbe stato creato per un canale vuoto, questo sarebbe trascurabile.

Tuttavia, mi aspetto che tutti i canali vuoti abbiano la stessa quantità di spazio, indipendentemente dal tipo sottostante, quindi se si intende chiudere solo il canale, non ci sarà alcuna differenza (un elemento reale sembra essere mantenuto da un puntatore). Un test rapido esegue il backup:

package main 

import (
    "fmt" 
    "time" 
) 

func main() { 
    // channel type 
    type xchan chan [64000]byte 
    a := make([]xchan, 10000000) // 10 million 
    for n := range a { 
     a[n] = make(xchan) 
    } 
    fmt.Println("done") 
    time.Sleep(time.Minute) 
} 

non vedo alcuna differenza tra chan struct{} e chan [64000]byte, entrambi i cavi a ~ 1 GB di utilizzo sulla mia macchina a 64 bit, il che mi fa credere che sovraccarico di creare un singolo canale da qualche parte circa 100 byte.

In conclusione, non importa. Personalmente userei lo struct{} perché è l'unico tipo veramente vuoto (di dimensioni 0 in effetti), che indica chiaramente che non c'è intensione di alcun payload inviato.