Какой тип канала использует наименьшее количество памяти в Go?

Я ловлю себя на том, что часто использую каналы, чтобы что-то остановить. В этих случаях канал используется исключительно как средство передачи сигналов, и фактически никакие данные не используются.

Например:

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

Запустите/просмотрите его на игровой площадке golang.


Мой вопрос:

Какой тип канала занимает меньше всего памяти в Go?

например Будет ли логический чейн требовать меньше накладных расходов, чем пустой struct{} chan?

chan bool

chan byte

chan interface{}

chan struct{}

...

что-то другое?


person Jay Taylor    schedule 10.06.2015    source источник
comment
Я не проверял в источнике, но я ожидаю, что накладные расходы самого канала будут преобладать над эффектом byte, bool или struct{} для небуферизованного канала.   -  person Volker    schedule 11.06.2015


Ответы (1)


Глядя на последнюю реализацию канала, это не тривиальная структура:

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
}

Элементы очередей ожидания также довольно тяжелые:

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
}

Видите ли, много байт. Даже если какой-либо элемент будет создан для пустого канала, это будет незначительно.

Однако я ожидаю, что все пустые каналы будут занимать одинаковое количество места, независимо от базового типа, поэтому, если вы собираетесь закрыть только канал, разницы не будет (похоже, фактический элемент удерживается указателем). Быстрый тест подтверждает это:

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)
}

Я не вижу разницы между chan struct{} и chan [64000]byte, оба приводят к использованию ~ 1 ГБ на моей 64-битной машине, что заставляет меня поверить, что накладные расходы на создание одного канала занимают где-то около 100 байт.

В заключение, это не имеет большого значения. Лично я бы использовал struct{}, так как это единственный действительно пустой тип (действительно с размером 0), ясно указывающий на отсутствие намерения отправлять какую-либо полезную нагрузку.

person tomasz    schedule 10.06.2015