Как настроить размер буфера для http.ResponseWriter?

# #http #go #buffer

Вопрос:

http.ResponseWriter имеет только две функции: одна есть WriteHeader() , другая есть Write() . Поэтому я считаю, что его нужно настроить в других местах. Затем я нашел это: https://golang.org/src/net/http/server.go L1534

 // 1. *response (the ResponseWriter) ->
// 2. (*response).w, a *bufio.Writer of bufferBeforeChunkingSize bytes
// 3. chunkWriter.Writer (whose writeHeader finalizes Content-Length/Type)
//    and which writes the chunk headers, if needed.
// 4. conn.buf, a bufio.Writer of default (4kB) bytes, writing to ->
// 5. checkConnErrorWriter{c}, which notes any non-nil error on Write
//    and populates c.werr with it if so. but otherwise writes to:
// 6. the rwc, the net.Conn.
 

Основываясь на моем тесте, размер буфера по умолчанию составляет 4 КБ. Я вижу, что это должно быть настраиваемо, но как? Кто-нибудь знает?

Комментарии:

1. В чем проблема, которую вы пытаетесь решить, регулируя размер буфера?

2. bufio.Writer реализовано таким образом, что фрагмент байтов, больший, чем размер буфера, записывается непосредственно в базовую запись (когда буфер не пуст, будет дополнительная запись). Поэтому, как правило, нет необходимости изменять этот размер. Можете ли вы написать, какую проблему вы пытаетесь решить?

3. У нас есть сервер, который генерирует аудиоданные, и он очень медленный. Скорость составляет около 4 Кб в 1,5 секунды. Таким образом, клиент начинает воспроизводить звук только через 1,5 секунды. К сожалению, я ничего не могу сделать, чтобы ускорить этот процесс. Единственное, что я могу сделать, — это оптимизировать время отклика.

4. После некоторой отладки я обнаружил, что если я смогу изменить размер буфера ответов на 2 КБ, то клиент сможет получить данные за 0,7 с и начать воспроизводить аудио.

5. @ EricYang Исправьте это, очистив автора ответа .

Ответ №1:

Я видел аналогичное требование и соответствующие изменения Server struct , которые были предложены в прошлом https://github.com/golang/go/issues/7467. Но было рекомендовано добавить собственную буферизацию к функциям обработчика, которые должны иметь буфер пользовательского размера.

Вы можете настроить размер буфера для http.ResponseWriter , обернув текущий http.ResponseWriter с помощью буфера записи пользовательского размера, как рекомендовано в выпуске github выше.

 package main

import (
    "bufio"
    "fmt"
    "io"
    "log"
    "net/http"
    "strings"
)

func main() {
    h1 := func(w http.ResponseWriter, _ *http.Request) {
        pw := bufio.NewWriterSize(w, 10<<10) // Bigger writer of 10kb
        fmt.Println("Buffer size", pw.Size())

        strR := strings.Repeat("Hello from a Func1!n", 1000) //just to create a bigger response

        _, err := io.WriteString(pw, strR)

        if err != nil {
            fmt.Println(err)
        }

        if pw.Buffered() > 0 {
            fmt.Println("Bufferred", pw.Buffered())
            pw.Flush() // Important step read my note following this code snippet
        }
    }

    h2 := func(w http.ResponseWriter, _ *http.Request) {
        io.WriteString(w, "Hello from a Func2!n")
    }

    http.HandleFunc("/foo", h1)
    http.HandleFunc("/bar", h2)

    log.Fatal(http.ListenAndServe(":8080", nil))
}
 

Примечание: Поскольку мы завернули оригинал http.ResponseWriter , нам нужно будет управлять сбросом буфера самостоятельно pw.Flush() , т. е. Как также упоминалось в документах.

Пишущие строки ответов, которые позволяют обработчику HTTP сбрасывать буферизованные данные клиенту.

Реализации пишущей машинки HTTP/1.x и HTTP/2 по умолчанию поддерживают Flusher, но оболочки пишущей машинки могут этого не делать. Обработчики всегда должны проверять эту способность во время выполнения.

Комментарии:

1. Спасибо, Ник!! Это именно то, что мне нужно!

2. К сожалению, функция Flush() не очистила данные, как я ожидал. Я думаю, что он переключился на пишущую машинку ответа, но пишущая машинка по-прежнему использовала свой собственный размер буфера 4K для передачи данных клиенту…

3. Это сработало для меня, когда я попробовал точный код, написанный в ответе. Поделитесь своим фрагментом кода через игровую площадку или что-то в этом роде.

4. Я запустил ваш код и сбросил TCP-трафик. вот что я нашел: вы можете видеть, что посылка все еще 4096. 14:53:32.833985 IP6 localhost.8181 > localhost.56416: Flags [P.], seq 1:4097, ack 82, win 6370, options [nop,nop,TS val 1329849328 ecr 1588922425], length 4096 | 14:53:32.833990 IP6 localhost.8181 > localhost.56416: Flags [P.], seq 4097:8193, ack 82, win 6370, options [nop,nop,TS val 1329849328 ecr 1588922425], length 4096

5. Я думаю, что вы имеете в виду приведенную выше строку OPTIONS с телом чтения, которое жестко закодировано до 4 кб, см. Здесь golang.org/src/net/http/server.go#L3403 .