многократное использование sync.WaitGroup - PullRequest
0 голосов
/ 15 декабря 2018

Я видел несколько разных примеров sync.WaitGroup

Пример 1

var wg sync.WaitGroup

wg.Add(1)
go doStuff(&wg)
wg.Wait()

Пример 2

wg := new(sync.WaitGroup)

wg.Add(1)
go doStuff(wg)
wg.Wait()

разница действительно в пути sync.WaitGroup инициализируется var против new

, если используется опция var, она должна быть передана как указатель &wg в программу, но если я использую опцию new, я могу отправитьэто как wg

В чем разница между двумя примерами?Какой из этих 2 выше является правильным?Является ли одно предпочтение перед другим в определенных ситуациях?

Я пишу программу, которая создает несколько sync.WaitGroup s, поэтому имеет ли значение, если используется new или var?

1 Ответ

0 голосов
/ 15 декабря 2018

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

var wg = &sync.WaitGroup{}

Методы sync.WaitGroup имеютполучатель указателя, поэтому всякий раз, когда вы вызываете его методы, требуется адрес значения структуры WaitGroup.Это не проблема, так как когда wg не является указателем, вызовы wg.Add(1) и wg.Done() являются сокращением для (&wg).Add(1) и (&wg).Done(), поэтому компилятор автоматически «переписывает» эти вызовы, чтобы получить адресиз wg и использовать этот адрес в качестве получателя методов.

Однако я все еще думаю, что если значение полезно только в качестве указателя (sync.WaitGroup - яркий пример), вам следуетобъявите его и в первую очередь работайте с ним как с указателем, так что остается меньше места для ошибок.

Например, если вы используете не указатель и объявляете функцию, ожидающую отсутствие указателя,и вы передадите его как не указатель, вы не получите ошибки во время компиляции, но он будет работать неправильно (sync.WaitGroup не должен копироваться).

Несмотря на то, что сегодняшний линтер выдаст вам предупреждающее сообщение, все жеЯ считаю, что лучше всего работать с указателями все время.

Еще одна причина работать с указателями: если функция вернет sync.WaitGroup, или если у вас есть карта, которая хранит sync.WaitGroup в качестве значений,ты не будешьВызвать методы для результата, потому что возвращаемые значения функций и операции индекса карты не адресуемы.Если функция возвращает значение указателя или если вы в первую очередь сохраняете указатели на карте, вы все равно можете вызывать методы, не сохраняя их в локальной переменной.Подробнее см. Как сохранить ссылку на результат операции в Go?

Например:

func getWg() sync.WaitGroup { return sync.WaitGroup{} }

getWg().Wait() // Compile-time error!

m := map[int]sync.WaitGroup{
    1: sync.WaitGroup{},
}

m[1].Wait() // Again: compile-time error

Но эти работы:

func getWg() *sync.WaitGroup { return &sync.WaitGroup{} }

getWg().Wait() // Works, you can call methods on the return value

m := map[int]*sync.WaitGroup{
    1: &sync.WaitGroup{},
}

m[1].Wait() // Also works

Подробнее об этом здесь: Зачем конструктору обратный адрес Go?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...