Функция io.Pipe

Функция io.Pipe создает синхронный конвейер, который связывает io.Reader и io.Writer. Она возвращает два значения: *io.PipeReader и *io.PipeWriter. Данные, записанные в writer, могут быть прочитаны из reader. Операции чтения и записи блокируются до тех пор, пока другая сторона не завершит свою операцию, что обеспечивает синхронную передачу данных.

Синтаксис

gofunc Pipe() (*PipeReader, *PipeWriter)

Пример

Давайте создадим конвейер и запишем строку в writer, а затем прочитаем ее из reader:

gopackage main

import (
  "fmt"
  "io"
)

func main() {
  reader, writer := io.Pipe()
  go func() {
    defer writer.Close()
    writer.Write([]byte("Hello, Pipe!"))
  }()
  data, err := io.ReadAll(reader)
  if err != nil {
    fmt.Printf("error: %v\n", err)
  }
  reader.Close()
  fmt.Println(string(data))
}

Результат выполнения кода:

go"Hello, Pipe!"

Пример

Давайте передадим данные через конвейер с использованием буфера и проверим, что чтение и запись синхронизированы:

gopackage main

import (
  "fmt"
  "io"
  "time"
)

func main() {
  reader, writer := io.Pipe()
  go func() {
    defer writer.Close()
    for i := 0; i < 3; i++ {
      time.Sleep(100 * time.Millisecond)
      writer.Write([]byte(fmt.Sprintf("message %d", i)))
    }
  }()
  buf := make([]byte, 20)
  for {
    n, err := reader.Read(buf)
    if err == io.EOF {
      break
    }
    if err != nil {
      fmt.Printf("error: %v\n", err)
      break
    }
    fmt.Printf("%s\n", string(buf[:n]))
  }
  reader.Close()
}

Результат выполнения кода:

go"message 0"
"message 1"
"message 2"

Пример

Давайте используем io.Pipe для соединения двух горутин, где одна генерирует данные, а другая их обрабатывает:

gopackage main

import (
  "fmt"
  "io"
  "strconv"
)

func main() {
  reader, writer := io.Pipe()
  go func() {
    defer writer.Close()
    for i := 1; i <= 5; i++ {
      writer.Write([]byte(strconv.Itoa(i) + "\n"))
    }
  }()
  go func() {
    defer reader.Close()
    buf := make([]byte, 10)
    for {
      n, err := reader.Read(buf)
      if err == io.EOF {
        break
      }
      if err != nil {
        fmt.Printf("error: %v\n", err)
        break
      }
      fmt.Printf("processed: %s", string(buf[:n]))
    }
  }()
  fmt.Scanln()
}

Результат выполнения кода:

go"processed: 1"
"processed: 2"
"processed: 3"
"processed: 4"
"processed: 5"

Смотрите также

  • интерфейс io.Reader,
    который определяет методы для чтения данных
  • интерфейс io.Writer,
    который определяет методы для записи данных
  • функцию io.Copy,
    которая копирует данные из reader в writer
  • функцию io.ReadAll,
    которая читает все данные из reader до EOF