Без изменения Logger можно сериализовать Log и Close обёрткой с mutex. Это обеспечивает согласованность, но не ускоряет сам диск и не создаёт определённый порядок одновременных вызовов заранее.
Оптимизируй производительность кода
Без изменения Logger можно сериализовать Log и Close обёрткой с mutex. Это обеспечивает согласованность, но не ускоряет сам диск и не создаёт определённый порядок одновременных вызовов заранее.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Требуется устранить узкие места, влияющие на скорость работы программы, при этом менять внутреннюю реализацию логгера нельзя.
type Logger interface {
Log(message string) error
Close() error
}
type FileLogger struct{ file *os.File }
func NewFileLogger(path string) (*FileLogger, error) {
fileHandle, err := os.Create(path)
if err != nil {
return nil, err
}
return &FileLogger{fileHandle}, nil
}
func (fl FileLogger) Log(message string) error {
_, err := fl.file.WriteString(message + "\n")
return err
}
func (fl FileLogger) Close() error {
return fl.file.Close()
}
// ...
type SequentialLogger struct {
inner Logger
}
func NewSequentialLogger(inner Logger) *SequentialLogger {
return &SequentialLogger{inner}
}
func (sl *SequentialLogger) Log(message string) error {
// TODO: добавить реализацию, сохраняющую порядок записи и не ухудшающую производительность
}
Ответ
Без изменения Logger можно сериализовать Log и Close обёрткой с mutex. Это обеспечивает согласованность, но не ускоряет сам диск и не создаёт определённый порядок одновременных вызовов заранее.
Импорты sync и errors; существующий конструктор замените на keyed literal &SequentialLogger{inner: inner}:
type SequentialLogger struct {
inner Logger
mu sync.Mutex
closed bool
}
func (sl *SequentialLogger) Log(message string) error {
sl.mu.Lock()
defer sl.mu.Unlock()
if sl.closed { return errors.New("logger closed") }
return sl.inner.Log(message)
}
func (sl *SequentialLogger) Close() error {
sl.mu.Lock()
defer sl.mu.Unlock()
if sl.closed { return nil }
sl.closed = true
return sl.inner.Close()
}
Порядок — порядок захвата lock; строгая внешняя последовательность требует номеров сообщений. Асинхронная очередь снижает задержку вызывающего, но меняет смысл возврата error и требует flush/backpressure. Без изменения гарантий нельзя обещать бесплатное ускорение.