Записать в exec.Cmd.StdinPipe () более 4 Кбайт

Проблема

При записи данных размером более 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.")
}

Проверенные версии

  • go версия go1.10.1 windows / amd64
  • версия go1.10.1 linux / amd64

Он должен иметь возможность продолжить запись, как только команда more считывает больше из конвейера.

Zan Lynx 01.05.2018 18:07
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
1
1
792
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Запись только блоков, если в конвейере больше нет места. Хотя размер канала в 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, но программа остановилась, как вы говорите!

Yujiro Takeda 01.05.2018 18:23

На этот вопрос уже был дан ответ, вот обходной путь, который вы, вероятно, захотите использовать, если столкнетесь с этой проблемой - вместо этого используйте буферизованный писатель, доступный в пакете Буфио. Это позволяет вам обернуть писатель буфером большего размера, над которым у вас есть полный контроль.

Или вместо того, чтобы буферизовать его дважды, вы пишете его изнутри в горутине, как показано в документации

JimB 01.05.2018 21:39

Да, я использовал оба метода. Если у вас большое количество писателей или вы пишете несколько раз, может быть сложно управлять горутиной для каждого писателя - запись в горутине может вызвать состояние гонки, если вы сделаете это более одного раза быстро. В этот момент вам нужно вместо этого перейти к каналу. Буферы иногда проще.

Sudhir Jonathan 02.05.2018 08:29

Другие вопросы по теме