При записи данных размером более 4096 байт в Cmd.StdinPipe
в Go обработка программы останавливается в Windows. Этого явления не происходит, когда один и тот же код работает в Linux, или при написании процесса с использованием goroutine.
Обработка не будет происходить из _, err = in.Write ([] byte {'0'})
(4097 байт) в коде, показанном ниже. Почему это?
Почему этого не происходит с горутиной или Linux?
*** Ссылка Golang описывает Cmd.StdinPipe с использованием goroutine как пример, и моя проблема также была решена. Этот вопрос возникает из-за любопытства по поводу Go.
package main
import (
"bytes"
"fmt"
"io"
"log"
"os/exec"
)
func main() {
cmd := exec.Command("more")
pype, err := cmd.StdinPipe()
if err != nil {
log.Fatal(err)
}
bytes4k := generateBytes(1024 * 4) // Works on Linux, but not Windows.
// bytes4k := generateBytes(1024 * 64) // Don't works on Linux and Windows.
fmt.Println("bytes generated.")
// go writeBytes(pype, bytes4k) // Works fine!
writeBytes(pype, bytes4k) // Can't write. Write is locked.
err = cmd.Run()
if err != nil {
log.Fatal(err)
}
fmt.Println("finished.")
}
func generateBytes(num int) []byte {
byte := bytes.NewBuffer(make([]byte, 0, num))
for i := 0; i < num; i++ {
byte.WriteByte('0')
}
return byte.Bytes()
}
func writeBytes(in io.WriteCloser, bytes []byte) {
defer in.Close()
_, err := in.Write(bytes)
if err != nil {
log.Fatal(err)
}
fmt.Println("written bytes to pipe.")
_, err = in.Write([]byte{'0'}) // Why this code stops at 4097 bytes?
if err != nil {
log.Fatal(err)
}
fmt.Println("written 1 byte to pipe.")
}
Запись только блоков, если в конвейере больше нет места. Хотя размер канала в Windows может составлять 4 КБ, в Linux он намного больше. От труба (7):
... Since Linux 2.6.11, the pipe capacity is 16 pages (i.e., 65,536 bytes in a system with a page size of 4096 bytes)...
Таким образом, вы, вероятно, получите тот же результат в Linux, что и в Windows, при записи в канал, где никто не читает, но вам нужно записать в канал намного больше данных, пока вы не достигнете этой ситуации.
Спасибо за ваш ответ! Я понял, почему приведенный выше код не работает в Windows. И причина того, почему горутин отлично работает, заключается в том, что она читается до того, как канал заполнится. Я попытался записать 65536 байт в Linux, но программа остановилась, как вы говорите!
На этот вопрос уже был дан ответ, вот обходной путь, который вы, вероятно, захотите использовать, если столкнетесь с этой проблемой - вместо этого используйте буферизованный писатель, доступный в пакете Буфио. Это позволяет вам обернуть писатель буфером большего размера, над которым у вас есть полный контроль.
Или вместо того, чтобы буферизовать его дважды, вы пишете его изнутри в горутине, как показано в документации
Да, я использовал оба метода. Если у вас большое количество писателей или вы пишете несколько раз, может быть сложно управлять горутиной для каждого писателя - запись в горутине может вызвать состояние гонки, если вы сделаете это более одного раза быстро. В этот момент вам нужно вместо этого перейти к каналу. Буферы иногда проще.
Он должен иметь возможность продолжить запись, как только команда
more
считывает больше из конвейера.