- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在Rust中制作一个小的ncurses应用程序,该应用程序需要与子进程进行通信。我已经有一个用Common Lisp编写的原型(prototype)。我试图重写它,因为CL为这么小的工具使用了大量的内存。
我在弄清楚如何与子流程进行交互时遇到了一些麻烦。
我目前正在做的大致是这样的:
let mut program = match Command::new(command)
.args(arguments)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
{
Ok(child) => child,
Err(_) => {
println!("Cannot run program '{}'.", command);
return;
}
};
fn listen_for_output(program: &mut Child, output_viewer: &TextViewer) {
match program.stdout {
Some(ref mut out) => {
let mut buf_string = String::new();
match out.read_to_string(&mut buf_string) {
Ok(_) => output_viewer.append_string(buf_string),
Err(_) => return,
};
}
None => return,
};
}
read_to_string
的调用将阻止程序,直到进程退出。从我可以看到的
read_to_end
和
read
似乎也阻止。如果我尝试运行立即退出的类似于
ls
的东西,它可以工作,但是对于没有退出的诸如
python
或
sbcl
的东西,它只有在我手动杀死该子进程后才继续。
BufReader
:
fn listen_for_output(program: &mut Child, output_viewer: &TextViewer) {
match program.stdout.as_mut() {
Some(out) => {
let buf_reader = BufReader::new(out);
for line in buf_reader.lines() {
match line {
Ok(l) => {
output_viewer.append_string(l);
}
Err(_) => return,
};
}
}
None => return,
}
}
BufReader
设置超时。
最佳答案
默认情况下,流被阻止。 TCP/IP流,文件系统流,管道流都被阻塞。当您告诉流为您提供大量字节时,它将停止并等待,直到它具有给定的字节数或发生其他事情为止(interrupt,流的末尾,错误)。
操作系统渴望将数据返回到读取过程中,因此,如果您只想等待下一行并尽快处理它,那么Shepmaster在Unable to pipe to or from spawned child process more than once中建议的方法(以及他在此处的回答) )的作品。
尽管从理论上讲它不必工作,因为允许操作系统使BufReader
等待read
中的更多数据,但实际上,操作系统更喜欢早期的“短读”而不是等待。
当您需要处理多个流(例如子进程的BufReader
和stdout
)或多个进程时,这种基于stderr
的简单方法会变得更加危险。例如,当子进程等待您耗尽其BufReader
管道,而您的进程因等待其空stderr
而被阻塞时,基于stdout
的方法可能会死锁。
同样,当您不希望程序无限期地等待子进程时,也不能使用BufReader
。也许您想在 child 仍在工作时显示进度条或计时器,却没有任何输出。
如果您的操作系统恰好不急于将数据返回给进程(首选“完全读取”而不是“短读取”),则不能使用基于BufReader
的方法,因为在这种情况下,子进程会打印最后几行可能会以灰色区域结尾:操作系统将其捕获,但是它们的大小不足以填充BufReader
的缓冲区。BufReader
限于Read
接口(interface)允许它对流执行的操作,它的阻止程度不亚于基础流。为了提高效率,它将以块的形式read输入,告诉操作系统填充尽可能多的可用缓冲区。
您可能想知道为什么在这里块读取数据如此重要,为什么BufReader
不能仅逐字节读取数据。问题是要从流中读取数据,我们需要操作系统的帮助。另一方面,我们不是操作系统,我们与它隔离工作,以免在我们的过程出现问题时避免困惑。因此,为了调用操作系统,需要过渡到“内核模式”,这也可能会导致“上下文切换”。这就是为什么调用操作系统读取每个字节很昂贵的原因。我们希望尽可能少的OS调用,因此我们可以分批获取流数据。
要在不阻塞的情况下等待流,您需要一个非阻塞流。 MIO promises to have the required non-blocking stream support for pipes,很可能是PipeReader,但到目前为止我还没有检查出来。
流的非阻塞性质应该使得可以分块读取数据,而不管操作系统是否喜欢“短读取”。因为非阻塞流永远不会阻塞。如果流中没有数据,它只会告诉您。
在没有非阻塞流的情况下,您将不得不诉诸于生成线程,以便阻塞读取将在单独的线程中执行,因此不会阻塞您的主线程。您可能还想逐字节读取流,以便在操作系统不喜欢“短读取”的情况下立即对行分隔符使用react。这是一个工作示例:https://gist.github.com/ArtemGr/db40ae04b431a95f2b78。
P.S.这是一个函数示例,该函数允许通过共享的字节向量监视程序的标准输出:
use std::io::Read;
use std::process::{Command, Stdio};
use std::sync::{Arc, Mutex};
use std::thread;
/// Pipe streams are blocking, we need separate threads to monitor them without blocking the primary thread.
fn child_stream_to_vec<R>(mut stream: R) -> Arc<Mutex<Vec<u8>>>
where
R: Read + Send + 'static,
{
let out = Arc::new(Mutex::new(Vec::new()));
let vec = out.clone();
thread::Builder::new()
.name("child_stream_to_vec".into())
.spawn(move || loop {
let mut buf = [0];
match stream.read(&mut buf) {
Err(err) => {
println!("{}] Error reading from stream: {}", line!(), err);
break;
}
Ok(got) => {
if got == 0 {
break;
} else if got == 1 {
vec.lock().expect("!lock").push(buf[0])
} else {
println!("{}] Unexpected number of bytes: {}", line!(), got);
break;
}
}
}
})
.expect("!thread");
out
}
fn main() {
let mut cat = Command::new("cat")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("!cat");
let out = child_stream_to_vec(cat.stdout.take().expect("!stdout"));
let err = child_stream_to_vec(cat.stderr.take().expect("!stderr"));
let mut stdin = match cat.stdin.take() {
Some(stdin) => stdin,
None => panic!("!stdin"),
};
}
通过几个帮助程序,我正在使用它来控制SSH session :
try_s! (stdin.write_all (b"echo hello world\n"));
try_s! (wait_forˢ (&out, 0.1, 9., |s| s == "hello world\n"));
P.S.请注意,async-std中的
read调用上的
await
也处于阻塞状态。它只是阻塞一个 future 链(本质上是一个无堆栈的绿色线程),而不是阻塞系统线程。
poll_read是非阻塞接口(interface)。在
async-std#499中,我问开发人员这些API是否有简短的读取保证。
关于process - 如何在不阻塞Rust的情况下读取子进程的输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59374194/
我遇到以下问题。我想读取一个包含数百万行和数百列的大型 csv。我想向下转换列的数据类型。我的方法是读取 csv,然后使用 pd.to_numeric() 对其进行向下转换。我不知道列数及其类型。在读
目前,我从 SQL server (2008) 数据库获取数据。 cyurrent的方法是使用DataTable,然后将其传递并使用。 if (parameters != null)
我有以下问题。我有一个巨大的 csv 文件,想用多处理加载它。对于一个包含 500000 行和 130 列不同数据类型的示例文件,Pandas 需要 19 秒。我试过 dask 因为我想多处理阅读。但
是否有关于用于序列化各种 MFC 数据结构的二进制格式的明确文档?我已经能够在十六进制编辑器中查看我自己的一些类,并使用 Java 的 ByteBuffer 类读取它们(使用自动字节顺序转换等)。 但
我正在使用 Selenium 进行测试,我们用 HTML 文件编写测试用例,并用它们制作测试套件,我们的要求是编写足够健壮的测试用例,以根据测试环境改变自身。 为此,我不希望在 HTML 脚本本身中包
我需要一个 JavaScript 代码来读取存储为 .txt 文件的字典(或者也可以保存为任何其他类型的文件。它也可以在线获得)并将其内容存储在一个变量中。我不能找到一种让 JavaScript 像
我正在尝试遍历包含 SSH 登录和其他日志的日志文本文件。 程序正在返回 SSH 登录的总数。 我的解决方案确实有效,但似乎有点慢(在 200mo 文件上大约需要 3.5 秒)。我想知道是否有任何方法
我正在将大量数据从一个电子表格复制到工作簿中的其他 160 个电子表格。目前,Excel (2013) 遇到错误,因为它没有足够的资源来完成操作。 我的目标是将工作表 4 中 V13:XI1150 范
我正在尝试读取一个有 1147 行的文本文件。下面的代码仅读取第 1050-1147 行。我的目标是读取整个文件并提取位于不同行的特定值以在脚本中使用。一个示例是包含“BlockList: 2”的行中
我正在为游戏编写解释器。用户将其移动输入解释器,程序执行该移动。 现在我想为每个决定实现一个时间限制。玩家不应该能够思考超过 30 秒来写一个移动并按下回车。 call_with_time_limit
以this file例如,我正在尝试读取 data.frame 中的数据。来自 the doc (pdf 文件,表 1),它遵循一些 fortran 约定。我尝试了以下但收效甚微: dir 0' 将
我正在使用 R 阅读 Outlook 附件。我的引用在这里:Download attachment from an outlook email using R 这是我的电子邮件的截图: 这每天都会发送
我不会从表格中读取行来将主题放在列表中 php脚本 $url_obj='http://'.$host.':8069/xmlrpc/object'; $sock=new xmlrpc_client($u
我有一个这样的 csv 文件: id,name,value 1,peter,5 2,peter\,paul,3 我如何读取此文件并告诉 R "\," 不表示新列,仅表示 ","。 我必须添加该文件
我正在尝试读取 ~/Library/Preferences/com.apple.mail.plist (在 Snow Leopard 上)以获取电子邮件地址和其他信息以进入“关于”对话框。我使用以下代
This question already has answers here: How do I use floating-point division in bash? (19个回答) 5个月前关闭
本练习的目标是读取输入文件并将其存储到表中,然后验证输入中的某些字段并输出任何错误记录。我需要读取并存储每个策略组,以便表中一次仅存储 5 条记录,而不是整个文件。 所以我需要读取一个包含 5 条记录
据我了解,LWT 插入始终以 SERIAL 一致性级别完成。如果为 true,这是否意味着读取作为 LWT 插入的行可以安全地以 ANY 的一致性级别读取? 换句话说,我假设 LWT 插入是完全一致的
我看到很多很多通过java脚本读取cookie的函数,但我只想在变量中使用它一次,我是JS新手。 这是我的代码 var TheNumber = (Math.random() + '') * 10000
我正在使用 asp.net 和 C#。我在服务器上部署了一个应用程序[已发布],现在我想查看该网站的代码,据我所知,我可以阅读程序集来查看代码。 请告诉我如何实现它。 提前致谢。 最佳答案 您可以使用
我是一名优秀的程序员,十分优秀!