Элементы «разыменования» в аргументах функции interface {} - PullRequest
0 голосов
/ 10 февраля 2019

У меня есть регистратор, который работает нормально, но производит довольно много накладных расходов в отношении выделения памяти.Ниже Debug() функция не печатает специально, потому что logOutputLevel недостаточно высока.

var logOutputLevel = 2
func Debug(s string, args ...interface{}) {
    if logOutputLevel > 1 { return }
    fmt.Printf(s, args...)
}

Тем не менее, этот метод производит довольно много ресурсов при передаче ему значений.При передаче указателей на него не выделяются большие ресурсы.См. Следующие тесты:

func BenchmarkLog(b *testing.B) {
    x := "abc"
    for n := 0; n < b.N; n++ {
        Debug("test %s", x)
    }
}

func BenchmarkLogRef(b *testing.B) {
    x := "abc"
    for n := 0; n < b.N; n++ {
        Debug("test %s", &x)
    }
}

Производит:

BenchmarkLog-8          50000000            43.1 ns/op        16 B/op          1 allocs/op
BenchmarkLogRef-8       500000000            3.17 ns/op        0 B/op          0 allocs/op

Теперь это все хорошо, и я пытаюсь переработать метод Debug(), чтобы он принимал только одну строку и неограниченные аргументы указателя только,Позже я хотел бы «разыменовать» все аргументы и передать их на fmt.Printf(), если уровень логирования достаточно высок.

Как мне этого добиться?Есть ли конкретная языковая идиома для «только указателей»?Я предполагаю, что ...*interface{} означает указатель на interface{} (а не любые значения должны быть указателем).

1 Ответ

0 голосов
/ 10 февраля 2019

Единственный способ предотвратить выделения - это не делать их в первую очередь.

Обычно это делается путем помещения оператора отладки в условный блок перед его оценкой:

if logOutputLevel > 1 {
    Debug("test: %s", x)
}

Вот как большинство пакетов журналов справляются с этим.См., Например, glog Verbose type .

Вы можете использовать теги build для условной компиляции функции Debug и полного игнорирования аргументов.Это не гарантирует языковая спецификация не выделять, но это оптимизация, которую компилятор может сделать в будущем, если текущая производительность приемлема.Используя два отдельных файла, вы можете переключаться между реализациями Debug во время компиляции:

debug.go

// +build debug

package main

import "log"

func Debug(fmt string, args ...interface{}) {
    log.Printf(fmt, args...)
}

release.go

// +build !debug

package main

func Debug(_ string, _ ...interface{}) {}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...