- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
在使用子进程并通过管道读取标准输出时,我注意到了一些有趣的行为。
如果我使用 io.Pipe()
读取通过 os/exec
创建的子进程的标准输出,即使达到 EOF,从该管道读取也会永远挂起(流程结束):
cmd := exec.Command("/bin/echo", "Hello, world!")
r, w := io.Pipe()
cmd.Stdout = w
cmd.Start()
io.Copy(os.Stdout, r) // Prints "Hello, World!" but never returns
但是,如果我使用内置方法 StdoutPipe()
它会起作用:
cmd := exec.Command("/bin/echo", "Hello, world!")
p := cmd.StdoutPipe()
cmd.Start()
io.Copy(os.Stdout, p) // Prints "Hello, World!" and returns
深入/usr/lib/go/src/os/exec/exec.go
的源代码,我可以看到StdoutPipe()方法实际上使用了os.Pipe ()
,而不是 io.Pipe()
:
pr, pw, err := os.Pipe()
cmd.Stdout = pw
cmd.closeAfterStart = append(c.closeAfterStart, pw)
cmd.closeAfterWait = append(c.closeAfterWait, pr)
return pr, nil
这给了我两条线索:
io.Pipe()
,而是 os.Pipe()
(一个较低级别的调用,大致映射到 pipe(2)
在 POSIX 中)被使用。但是,在考虑了这些新发现的知识后,我仍然无法理解为什么我的原始示例的行为方式如此。
如果我尝试关闭 io.Pipe()
(而不是 os.Pipe()
)的写端,那么它似乎会完全破坏它并且没有任何内容被读取(就像我正在从一个封闭的管道中读取一样,即使我认为我将它传递给了子进程):
cmd := exec.Command("/bin/echo", "Hello, world!")
r, w := io.Pipe()
cmd.Stdout = w
cmd.Start()
w.Close()
io.Copy(os.Stdout, r) // Prints nothing, no read buffer available
好吧,所以我猜 io.Pipe()
与 os.Pipe()
完全不同,并且可能不像 Unix 管道那样close()
不会为所有人关闭它。
只是为了让您不要认为我要求快速修复,我已经知道我可以通过使用此代码实现我的预期行为:
cmd := exec.Command("/bin/echo", "Hello, world!")
r, w, _ := os.Pipe() // using os.Pipe() instead of io.Pipe()
cmd.Stdout = w
cmd.Start()
w.Close()
io.Copy(os.Stdout, r) // Prints "Hello, World!" and returns on EOF. Works. :-)
我要问的是为什么 io.Pipe() 似乎忽略了作者的 EOF,让读者永远阻塞?一个有效的答案可能是 io.Pipe()
是错误的工具,因为 $REASONS
但我无法弄清楚那些 $REASONS
是因为根据文档,我正在尝试做的事情似乎完全合理。
这里有一个完整的例子来说明我在说什么:
package main
import (
"fmt"
"os"
"os/exec"
"io"
)
func main() {
cmd := exec.Command("/bin/echo", "Hello, world!")
r, w := io.Pipe()
cmd.Stdout = w
cmd.Start()
io.Copy(os.Stdout, r) // Blocks here even though EOF is reached
fmt.Println("Finished io.Copy()")
cmd.Wait()
}
最佳答案
“为什么 io.Pipe() 似乎忽略了作者的 EOF,让读者永远阻塞?”因为没有“作者的EOF”之类的东西。所有 EOF(在 unix 中)都向读者表明没有进程保持管道的写入端打开。当进程试图从没有写入器的管道中读取时,read
系统调用返回一个值,该值方便地命名为 EOF。由于您的 parent 仍然打开了管道写入端的一个副本,因此 read
block 。停止将 EOF 视为一件事。它只是一种抽象,作者从不“发送”它。
关于go - 为什么即使达到 EOF io.Pipe() 也会继续阻塞?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47486128/
我有管道输出 command_a | command_b | ... | command_n 输出是一个数字序列 4.2 -1 ... 0.2 我可以使用 gnuplot 绘制这些数字吗? (将 gn
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 6 年前。 Improv
我目前正在尝试连接父项和子项之间的管道。子级正在执行 sort 并对从父级接收到的输入进行排序。然后 children 写入一个单独的管道。每个进程有两个管道。一个这样 parent 可以将输入发送给
最近我正在研究 Python 中的并行编程工具。这是 os.pipe 和 multiprocessing.Pipe 之间的两个主要区别。(尽管它们被使用的场合) os.pipe是单向,multipro
我的站点上运行着 Yahoo Pipe,Romneyomics它使用来自 Delicious 和 Topsy 的饲料。Delicious 提要不提供“描述”字段,但 Topsy 提供,并且不仅仅是一个
我有一些使用管道的 Haskell 代码: module Main(main) where import Pipes a :: Producer Int IO () a = each [1..10]
所以标题几乎解释了我的问题。 stdout=subprocess.PIPE 和 stdout=PIPE 有什么区别?两者都来自 subprocess 模块,但为什么要使用一个而不是另一个呢?你如何使用
我有一个名为“myPipe”的自定义管道。我得到: The pipe 'myPipe' could not be found error 在我的单元测试中请建议在我的 .spec.ts 中导入和声明什
我有一个非常简单的 Python 3 脚本: f1 = open('a.txt', 'r') print(f1.readlines()) f2 = open('b.txt', 'r') print(f
我正在使用管道和 Python 的多处理模块在进程之间发送简单的对象。文档指出,如果管道已关闭,则调用 pipe.recv() 应该引发 EOFError。相反,我的程序只是阻塞在 recv() 上,
我在 perl 中见过这两种形式的管道 open。 一种是简单的管道打开 open FH,'| command'; 其他是安全管道打开 open FH,'|-','command'; 现在,第二个中的
我正在尝试对我的组件进行单元测试,但它立即生成一个错误: 类型错误:this.store$.pipe 不是函数 根据我的理解, createSpyObj 应该模拟状态。我有不同的选项选项,但没有一个起
我在这里看到这个帖子很多次了;但未能从命令中捕获故意错误。迄今为止我找到的最好的部分工作.. from Tkinter import * import os import Image, ImageTk
我正在编写一个简单的程序来解析编译器的输出并重新格式化任何错误消息,以便我们使用的 IDE(visual studio)可以解析它们。我们使用 nmake构建,它将使用如下命令行调用编译器: cc16
我有一个在coreos上运行的kubernetes集群。我希望在称为记录的Pod中的容器中运行journal2gelf https://github.com/systemd/journal2gelf。
为什么当管道中没有写入器时,读取器存在可以,但当管道中没有读取器时,写入器存在就不行? 。是不是因为reader需要等待,所以没有writer也没关系,而writer已经准备好数据了,即使数据准备好了
我在/etc/postfix/master.cf 中创建了一个 postfix 命令管道,其中包含一个在 STDOUT 和 STDERR 上产生输出的有效命令。在终端上调用时一切正常(因此在 STDO
我有一个命令需要来自管道的输入。例如,考虑著名的 cat 命令: $ echo Hello | cat Hello 假设我在 Perl 6 程序中有一个字符串,我想将其通过管道传递给命令: use v
因此,由于我们拥有各种设置,我习惯于遇到需要将一个可观察结果添加到另一个结果的地方,然后同时使用两者。我需要第一个在另一个之前完成的地方 getUser() .pipe( mergeMap
我在 Angular 5 中有一个非常简单的管道 import { Pipe, Injectable } from '@angular/core'; @Pipe({ name: "defaul
我是一名优秀的程序员,十分优秀!