go channel 概述 - 管道
概述
unix/linux OS 的一个进程的输出可以是另一个进程的输入,这些进程使用stdin与stdout设备作为通道,在进程之间传递数据。
同样的,GO中有io.Reader与io.Writer两个接口,如果要对一个设备进行读/写,调用实现了这两个接口的方法即可。
GO对管道的支持
- func t1() {
- cmd0 := exec.Command("echo","-n","how are you")
- fmt.Println(cmd0)
- }
exec.Command返回的对象的几个主要方法:
- // Stdin specifies the process's standard input.
- //
- // If Stdin is nil, the process reads from the null device (os.DevNull).
- //
- // If Stdin is an *os.File, the process's standard input is connected
- // directly to that file.
- //
- // Otherwise, during the execution of the command a separate
- // goroutine reads from Stdin and delivers that data to the command
- // over a pipe. In this case, Wait does not complete until the goroutine
- // stops copying, either because it has reached the end of Stdin
- // (EOF or a read error) or because writing to the pipe returned an error.
- Stdin io.Reader
- // Stdout and Stderr specify the process's standard output and error.
- //
- // If either is nil, Run connects the corresponding file descriptor
- // to the null device (os.DevNull).
- //
- // If either is an *os.File, the corresponding output from the process
- // is connected directly to that file.
- //
- // Otherwise, during the execution of the command a separate goroutine
- // reads from the process over a pipe and delivers that data to the
- // corresponding Writer. In this case, Wait does not complete until the
- // goroutine reaches EOF or encounters an error.
- //
- // If Stdout and Stderr are the same writer, and have a type that can
- // be compared with ==, at most one goroutine at a time will call Write.
- Stdout io.Writer
- Stderr io.Writer
示例
- /*
- 参数传入的是命令组
- 通过buffer一次次读取返回结果,不怕返回的数据量大
- 如果命令是shell那样有|管道符,则使用Pip方法即可
- */
- func PipCmd(cmd []string,useBufferIO... bool) string {
- useBufferedIO := false
- ll := len(useBufferIO)
- if ll > 0 {
- useBufferedIO = useBufferIO[0]
- }
- cmd0 := Command(cmd)
- stdout0, err := cmd0.StdoutPipe()
- if err != nil {
- fmt.Printf("Error: Couldn't obtain the stdout pipe for command : %s\n", err)
- return ""
- }
- defer stdout0.Close()
- if err := cmd0.Start(); err != nil {
- fmt.Printf("Error: The command can not be startup: %s\n", err)
- return ""
- }
- if !useBufferedIO {
- var outputBuf0 bytes.Buffer
- for {
- tempOutput := make([]byte, 1024)
- n, err := stdout0.Read(tempOutput)
- if err != nil {
- if err == io.EOF {
- break
- } else {
- fmt.Printf("Error: Couldn't read data from the pipe: %s\n", err)
- return ""
- }
- }
- if n > 0 {
- outputBuf0.Write(tempOutput[:n])
- }
- }
- //fmt.Printf("%s\n", outputBuf0.String())
- res := fmt.Sprintf("%v",outputBuf0.String())
- return res
- } else {
- outputBuf0 := bufio.NewReader(stdout0)
- var resBuffer bytes.Buffer
- for{
- //outputBuf0 默认带一个4K的缓冲区,第二个参数为false表示读取完所有的行
- output0, _, err := outputBuf0.ReadLine()
- if err != nil {
- if err == io.EOF{
- break
- }
- fmt.Printf("Error: Couldn't read data from the pipe: %s\n", err)
- return ""
- }
- output0 = append(output0,'\n')
- resBuffer.Write(output0)
- }
- res := fmt.Sprintf("%v",resBuffer.String())
- return res
- }
- }
- func Command(cmds []string) *exec.Cmd {
- name:= cmds[0]
- cmd := &exec.Cmd{
- Path: name,
- Args: cmds,
- }
- if filepath.Base(name) == name {
- if lp, err := exec.LookPath(name); err != nil {
- //cmd.lookPathErr = err
- ErrorHandle(err)
- } else {
- cmd.Path = lp
- }
- }
- return cmd
- }
- func a11() {
- //命令行参数不能包含空格,比如-ht 是错的,-ht是对的
- cmd := []string{"/opt/wks/go/dbm_go/src/dbm/consistency/consis_0.6.7", "-cht", "192.168.177.67", "-cpt", "3316", "-ht","114.67.105.113,192.168.177.67", "-pt","3306,3316", "-slot", "-json", "-db", "vodb", "-timeStart", "2020-09-11 14:09:27", "-pl", "2"}
- res := tools.PipCmd(cmd,true)
- fmt.Println(res)
- }
管道的返回值
- stdout0, err := cmd0.StdoutPipe()
- // StdoutPipe returns a pipe that will be connected to the command's
- // standard output when the command starts.
- //
- // Wait will close the pipe after seeing the command exit, so most callers
- // need not close the pipe themselves. It is thus incorrect to call Wait
- // before all reads from the pipe have completed.
- // For the same reason, it is incorrect to call Run when using StdoutPipe.
- // See the example for idiomatic usage.
- func (c *Cmd) StdoutPipe() (io.ReadCloser, error) {
- if c.Stdout != nil {
- return nil, errors.New("exec: Stdout already set")
- }
- if c.Process != nil {
- return nil, errors.New("exec: StdoutPipe after process started")
- }
- pr, pw, err := os.Pipe()
- if err != nil {
- return nil, err
- }
- c.Stdout = pw
- c.closeAfterStart = append(c.closeAfterStart, pw)
- c.closeAfterWait = append(c.closeAfterWait, pr)
- return pr, nil
- }
管道返回一个
- io.ReadCloser
- // ReadCloser is the interface that groups the basic Read and Close methods.
- type ReadCloser interface {
- Reader
- Closer
- }
不仅实现了读接口,还可以进行关闭操作
管道的内部实现
- pr, pw, err := os.Pipe()
系统创建了一个管道Pipe,内部加了读锁syscall.RorkLock.RLock(),然后返回一个读文件句柄pr,和一个写文件句柄pw
- // Pipe returns a connected pair of Files; reads from r return bytes written to w.
- // It returns the files and an error, if any.
- func Pipe() (r *File, w *File, err error) {
- var p [2]int
- e := syscall.Pipe2(p[0:], syscall.O_CLOEXEC)
- // pipe2 was added in 2.6.27 and our minimum requirement is 2.6.23, so it
- // might not be implemented.
- if e == syscall.ENOSYS {
- // See ../syscall/exec.go for description of lock.
- syscall.ForkLock.RLock()
- e = syscall.Pipe(p[0:])
- if e != nil {
- syscall.ForkLock.RUnlock()
- return nil, nil, NewSyscallError("pipe", e)
- }
- syscall.CloseOnExec(p[0])
- syscall.CloseOnExec(p[1])
- syscall.ForkLock.RUnlock()
- } else if e != nil {
- return nil, nil, NewSyscallError("pipe2", e)
- }
- return newFile(uintptr(p[0]), "|0", kindPipe), newFile(uintptr(p[1]), "|1", kindPipe), nil
- }
读方法
- // Reader is the interface that wraps the basic Read method.
- //
- // Read reads up to len(p) bytes into p. It returns the number of bytes
- // read (0 <= n <= len(p)) and any error encountered. Even if Read
- // returns n < len(p), it may use all of p as scratch space during the call.
- // If some data is available but not len(p) bytes, Read conventionally
- // returns what is available instead of waiting for more.
- //
- // When Read encounters an error or end-of-file condition after
- // successfully reading n > 0 bytes, it returns the number of
- // bytes read. It may return the (non-nil) error from the same call
- // or return the error (and n == 0) from a subsequent call.
- // An instance of this general case is that a Reader returning
- // a non-zero number of bytes at the end of the input stream may
- // return either err == EOF or err == nil. The next Read should
- // return 0, EOF.
- //
- // Callers should always process the n > 0 bytes returned before
- // considering the error err. Doing so correctly handles I/O errors
- // that happen after reading some bytes and also both of the
- // allowed EOF behaviors.
- //
- // Implementations of Read are discouraged from returning a
- // zero byte count with a nil error, except when len(p) == 0.
- // Callers should treat a return of 0 and nil as indicating that
- // nothing happened; in particular it does not indicate EOF.
- //
- // Implementations must not retain p.
- type Reader interface {
- Read(p []byte) (n int, err error)
- }
实现读接口的对象,有一个Read方法,可以将字节读到字节数组中; 与stdin设备对应,从该设备读取字节到内存。
- exec.Cmd这是一个外部命令,它可以是一个静止的命令,或者一个正在运行的命令;提供启动/停止/管道/输入输入定向支持;其中管道返回一个读文件句柄和一个写文件句柄
exec.Cmd输入输出重定向
- func runCmdWithPipe() {
- fmt.Println("Run command `ps -ef | grep apipe`: ")
- cmd1 := exec.Command("ps", "-ef")
- cmd2 := exec.Command("grep", "apipe")
- var outputBuf1 bytes.Buffer
- cmd1.Stdout = &outputBuf1
- if err := cmd1.Start(); err != nil {
- fmt.Printf("Error: The first command can not be startup %s\n", err)
- return
- }
- if err := cmd1.Wait(); err != nil {
- fmt.Printf("Error: Couldn't wait for the first command: %s\n", err)
- return
- }
- cmd2.Stdin = &outputBuf1
- var outputBuf2 bytes.Buffer
- cmd2.Stdout = &outputBuf2
- if err := cmd2.Start(); err != nil {
- fmt.Printf("Error: The second command can not be startup: %s\n", err)
- return
- }
- if err := cmd2.Wait(); err != nil {
- fmt.Printf("Error: Couldn't wait for the second command: %s\n", err)
- return
- }
- fmt.Printf("%s\n", outputBuf2.Bytes())
- }
go channel 概述 - 管道的更多相关文章
- Channel概述
前言 前两篇文章介绍了NIO核心部分部分之一的缓冲区的相关内容,接下来我们继续学习NIO中另一个重要的核心部分--Channel(通道). 在学习这篇文章之前,先做下简单的说明,本文是一篇关于通道的概 ...
- go channel 概述
精髓 将资源读进内存-->共享内存,一个个进程/线程进行处理,这是常见模式.go channel 是一种直接在进程/线程之间传递资源的方式,即以通信来共享内存.这便是go的精髓. 扩展-一些名词 ...
- [Go] 利用channel形成管道沟通循环内外
这个要解决的问题是,比如如果有一个大循环,取自一个大的文件,要进行逻辑处理,那么这个逻辑的代码要放在循环每一行的循环体里面,这样有可能会出现一个for循环的逻辑嵌套,一层又一层,类似俄罗斯套娃.如果放 ...
- GO 总章
GO 学习资源 go 代理 GO 语言结构 GO 数字运算 GO 时间处理 GO 定时器 GO 异常处理 go recover让崩溃的程序继续执行 GO Exit Fatal panic GO 通过进 ...
- GoLang的概述
GoLang的概述 1.什么是程序 完成某个功能的指令的集合 2.Go语言的诞生小故事 2.1. 开发团队-三个大牛 2.2.Google创造Golang的原因 2.3.Golang 的发展历程 20 ...
- 第四章:管道与FIFO
4.1:概述 管道是最初的Unix IPC形式,可追溯到1973年的Unix第三版.尽管对于许多操作来说很有用,但它们的根本局限在于没有名字,从而只能由亲缘关系的进程使用.这一点随FIFO的加入得改正 ...
- 第4章 管道与FIFO
4.1 概述 管道只在亲缘进程间使用,FIFO在任意进程间使用 4.2 管道 #include <unistd.h> ]) fd[0]用来读管道,fd[1]用来写管道 1)命令who | ...
- Go语言学习笔记(七)杀手锏 Goroutine + Channel
加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 Goroutine Go语言的主要的功能在于令人简易使用的并行设计,这个方法叫做Goroutine,通过Gorou ...
- go语言之行--golang核武器goroutine调度原理、channel详解
一.goroutine简介 goroutine是go语言中最为NB的设计,也是其魅力所在,goroutine的本质是协程,是实现并行计算的核心.goroutine使用方式非常的简单,只需使用go关键字 ...
随机推荐
- Python常用的数据文件存储的4种格式(txt/json/csv/excel)及操作Excel相关的第三方库(xlrd/xlwt/pandas/openpyxl)(2021最新版)
序言:保存数据的方式各种各样,最简单的方式是直接保存为文本文件,如TXT.JSON.CSV等,除此之外Excel也是现在比较流行的存储格式,通过这篇文章你也将掌握通过一些第三方库(xlrd/xlwt/ ...
- Redis INFO CPU 信息详解
一.INFO CPU 通过INFO CPU命令可以查看Redis进程对于CPU的使用情况,如下: 这几个字段的含义如下所示: used_cpu_sys: System CPU consumed by ...
- 手把手从0到1:搭建Kubernetes集群
搭建 k8s 集群网上很多教程,如果是手工部署或者实验环境可以直接使用 MiniKube 或者 Kind,来在本地启动简单的 Kubernetes 集群进行后面的学习即可.如果是使用 MiniKube ...
- 【数据结构&算法】09-队列概念&参考源码
目录 前言 队列的定义 队列的抽象数据类型 循环队列与链式队列对比 循环队列 特点 定义 循环队列相关计算 链式队列 定义 阻塞队列 并发队列 代码实现 循环队列代码 链式队列实现 前言 李柱明博客: ...
- 大一C语言学习笔记(2)---快捷键篇
大家好,博主呢,是一位刚刚步入大一的软件工程专业的大学生,之所以写博客,是想要与同样刚刚接触程序员一行的朋友们一起讨论,进步,在这里记录我的一些学习笔记及心得,希望通过这些点点滴滴的努力,可以让我们离 ...
- python实现高斯滤波
一,定义 核是:3 *3 均值滤波 二,高斯函数 Y方向的方差与X方向的一致.处理后图像看起来更模糊(滤波明显)的话,核要更大. (三)代码实现 (四)核计算 (五)图像产生高斯噪声循环代码实 ...
- [luogu5163]WD与地图
将删边改为插边,如果是无向图直接线段树合并即可,考虑如何将有向边转换为无向边 令$t_{i}$表示当插入到第$t_{i}$条边时恰好满足$x_{i}$与$y_{i}$在同一个强连通分量中,然后分类讨论 ...
- HDC技术分论坛:HarmonyOS新一代UI框架的全面解读
作者:yuzhiqiang,UI编程框架首席技术专家 在Harmony 3.0.0开发者预览版中,包含了新一代的声明式UI框架ArkUI 3.0.多语言跨平台编译器ArkCompiler 3.0.跨端 ...
- stat命令的实现-mysate(必做)
学习使用stat(1),并用C语言实现 1. 提交学习stat(1)的截图 使用 man 1 stat 查看帮助手册 从图中可以看到stat的用法是display file or file syste ...
- 【状压dp】Hamiton路径
描述 给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径. Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点 ...