为什么 Command 的 stdin write_all永远不会终止?



我有以下代码。运行python3 solution.py,stdin由变量input

提供
let mut cmd = Command::new("python3");
let mut child = cmd
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.arg("solution.py")
.spawn()
.expect("Failed to execute solution");
println!("Writing to stdin");
child
.stdin
.as_mut()
.unwrap()
.write_all(input.as_bytes())
.unwrap();
//never printed
println!("Finish writing to stdin");
child.stdin.as_mut().unwrap().flush().unwrap()

input变量很小时,它总是运行正常(并且很快终止)。但是当它达到~3MB(大字符串)时,它永远不会终止。我猜是死锁,因为CPU使用率很小。

你能建议如何使它运行与大input?为什么它似乎陷入僵局?

solution.py的简化版本,这个问题仍然发生(它只是打印空白字符串):

t = int(input())
for tt in range(t):
input()
res = [' '] * 1000
result = ''.join(res)
print("Case #{}: {}".format(tt+1, result))
有趣的是,如果我把第4行改成下面,程序将终止
res = [' '] * 100

这可能是由于大的输出尺寸?

你的Rust程序正在写一个连接到子进程stdin的管道。子进程正在写入其标准输出,标准输出也是一个管道。操作系统正在为两个管道缓冲一定数量的数据,但是当缓冲区满时,它将等待读端的进程消耗数据,然后再接受任何进一步的写入。

write_all()调用不断地向stdin管道写入数据,这些数据由子进程读取。子进程写入数据到stdout烟斗,但是没有人消费数据。一旦标准输出管道缓冲区填满,子进程就会阻止进一步写入数据,因此它会停止从标准输出管道读取数据。这意味着标准输入管道缓冲区也将被填满,此时父进程在试图写入更多数据时也会阻塞。

解决这个问题的最简单方法是将写入标准输入管道的操作移到线程中,并在主线程中添加从标准输出读取的代码。这样,您的Rust程序并行地读取和写入数据,并且不会发生死锁。std::process的文档中有一个示例来演示这种方法。

接受的答案解释了潜在的问题,并给出了如何使用标准库解决它的指导。

除此之外,您还可以使用subprocesscrate,其communicate()方法(以Python的Popen.communicate()为模型)旨在防止在类似您的情况下出现死锁:

let (out, _) = subprocess::Exec::cmd("python3")
.arg("solution.py")
.stdin("some data")
.communicate()?
.read_string()?;
// out is a String

声明:我是subprocess的作者。

相关内容

  • 没有找到相关文章