ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

管道

2021-01-14 02:32:04  阅读:19  来源: 互联网

标签:return err nil fmt 管道 Printf


匿名管道

介绍

• 是一种半双工(或者说单向)的通信方式,只能用于父进程与子进程以及同祖先的子进程之间的通信。
• 管道的优点在于简单,缺点则是只能单向通信以及对通信双发关系上的严格限制。
shell命令
• 使用shell命令时,常常会用到管道 ps aux | grep go shell会为每一个命令创建一个进程,然后把左边的命令的标准输出用管道与右边命令的标准输入连接起来。

go语言

• Go支持管道,通过标准库代码包os/exec中的API,可以执行操作系统命令并在此之上建立管道。

    // 创建命令
    cmd := exec.Command("echo", "-n", "My first command")
    // 获得一个输出管道
    stdout, err := cmd.StdoutPipe()
    if err != nil {
        fmt.Printf("get stdout pipe fail err=%v\n", err)
        return 
    }
    // 执行命令
    err = cmd.Start()
    if err != nil {
        fmt.Printf("start command fail err=%v\n", err)
        return 
    }
    // 读取管道信息
    data := make([]byte, 20)
    n, err := stdout.Read(data)
    if err != nil {
        fmt.Printf("read from pipe err=%v\n", err)
        return 
    }
    fmt.Println(string(data[:n]))
    // 连接两条命令 第一条命令的输出第二条命令的输入
    cmd1 := exec.Command("ps", "aux")
    cmd2 := exec.Command("grep", "go")
    var outputBuf1 bytes.Buffer
    // 设置输出
    cmd1.Stdout = &outputBuf1
    err := cmd1.Start()
    if err != nil {
        fmt.Printf("start command1  err=%v\n", err)
        return
    }
    // 等待命令执行完毕
    err = cmd1.Wait()
    if err != nil {
        fmt.Printf("wait command1 err=%v\n", err)
        return
    }
    // 将命令1的输出作为命令2的输入
    cmd2.Stdin = &outputBuf1
    var outputBuf2 bytes.Buffer
    cmd2.Stdout = &outputBuf2
    err = cmd2.Start()
    if err != nil {
        fmt.Printf("start command2  err=%v\n", err)
        return
    }
    err = cmd2.Wait()
    if err != nil {
        fmt.Printf("wait command2 err=%v\n", err)
        return
    }
    fmt.Println(outputBuf2.String())

命名管道

介绍

• 与匿名管道不同的是任何进程都可以用过命名管道交换数据。实际上,命名管道以文件的形式存在文件系统中,使用它的方法与使用文件很类似。
注意 命名管道默认是阻塞式的,更具体地说,只有对这个管道的读和写的操作都准备就绪的时候,数据才开始流动。命名管道仍是单向的,又由于可以实现多路复用,所以有时候也要考虑多个进程同时向命名管道写数据的情况下的原子性问题。

go语言

• Go标准库os包中,含有创建此类管道的API

    // 获得读写管道
    // 虽然r,w 都是*os.File类型但是r只能读,w只能写,否则会报错。
    r, w, err := os.Pipe()
    if err != nil {
        fmt.Printf("get read and write pipe fail err=%v\n", err)
        return
    }
    content := "just for test"
    // 测试发现 顺序执行以下语句 并没有发生阻塞
    // 先读后写会发生阻塞
    _, err = w.Write([]byte(content))
    if err != nil {
        fmt.Printf("write fail err=%v\n", err)
        return
    }
    data := make([]byte, len(content))
    _, err = r.Read(data)
    if err != nil {
        fmt.Printf("write fail err=%v\n", err)
        return
    }
    fmt.Println(string(data))

• os.Pipe() 函数生成的管道在底层是由操作系统级别的管道支持的,所以使用它们的时候要注意操作系统级别对管道的限制。例如,匿名管道会在管道缓冲区被写满后使写数据的进程阻塞,以及命名管道会在其中一端未就绪的情况下阻塞另一端的进程。
强调 命名管道可以被多路复用,所以,当有多个输入端写入数据时,不得不考虑操作原子性问题。操作系统提供的管道是不提供原子操作支持的。因此Go在标准库io包中提供了基于内存的有原子性操作保证的管道。
r,w := io.Pipe() 且返回的第一个参数只提供读方法没有写方法 第二个参数只能写不能读。同样需要两端准备就绪。

标签:return,err,nil,fmt,管道,Printf
来源: https://www.cnblogs.com/cwww/p/14275286.html

专注分享技术,共同学习,共同进步。侵权联系[admin#icode9.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有