tôi đã đi qua các tài liệu của open3 và đây là phần mà tôi không thể hiểu:Tại sao IPC :: Open3 bị bế tắc?
If you try to read from the child's stdout writer and their stderr writer, you'll have problems with blocking, which means you'll want to use select() or the IO::Select, which means you'd best use sysread() instead of readline() for normal stuff.
This is very dangerous, as you may block forever. It assumes it's going to talk to something like bc, both writing to it and reading from it. This is presumably safe because you "know" that commands like bc will read a line at a time and output a line at a time. Programs like sort that read their entire input stream first, however, are quite apt to cause deadlock.
Vì vậy, tôi đã cố gắng ra open3
hy vọng sẽ biết nó tốt hơn. Đây là nỗ lực đầu tiên:
sub hung_execute {
my($cmd) = @_;
print "[COMMAND]: $cmd\n";
my $pid = open3(my $in, my $out, my $err = gensym(), $cmd);
print "[PID]: $pid\n";
waitpid($pid, 0);
if(<$err>) {
print "[ERROR] : $_" while(<$err>);
die;
}
print "[OUTPUT]: $_" while (<$out>);
}
Thật thú vị khi lưu ý rằng tôi phải khởi tạo $err
tại đây.
Dù sao, điều này chỉ bị treo khi tôi execute("sort $some_file");
cho rằng $some_file
là tệp văn bản chứa hơn 4096 ký tự (giới hạn cho máy của tôi).
sau đó tôi nhìn vào this FAQ, và dưới đây là phiên bản mới của tôi thực hiện:
sub good_execute {
my($cmd) = @_;
print "[COMMAND]: $cmd\n";
my $in = gensym();
#---------------------------------------------------
# using $in, $out doesn't work. it expects a glob?
local *OUT = IO::File->new_tmpfile;
local *ERR = IO::File->new_tmpfile;
my $pid = open3($in, ">&OUT", ">&ERR", $cmd);
print "[PID]: $pid\n";
waitpid($pid, 0);
seek $_, 0, 0 for \*OUT, \*ERR;
if(<ERR>) {
print "[ERROR] : $_" while(<ERR>);
die;
}
print "[OUTPUT]: $_" while (<OUT>);
}
Lệnh sort
thực hiện tốt bây giờ, nhưng tôi không thể tìm ra lý do tại sao.
[Cập nhật] Sau khi đọc câu trả lời @ tchrist, tôi đọc IO::Select
, và sau khi một số googling hơn, đã đưa ra phiên bản này của execute
:
sub good_execute {
my($cmd) = @_;
print "[COMMAND]: $cmd\n";
my $pid = open3(my $in, my $out, my $err = gensym(), $cmd);
print "[PID]: $pid\n";
my $sel = new IO::Select;
$sel->add($out, $err);
while(my @fhs = $sel->can_read) {
foreach my $fh (@fhs) {
my $line = <$fh>;
unless(defined $line) {
$sel->remove($fh);
next;
}
if($fh == $out) {
print "[OUTPUT]: $line";
}elsif($fh == $err) {
print "[ERROR] : $line";
}else{
die "[ERROR]: This should never execute!";
}
}
}
waitpid($pid, 0);
}
này đang làm việc tốt, và một vài điều giờ đã trở nên rõ ràng hơn. Nhưng bức tranh tổng thể vẫn còn hơi mờ.
Vì vậy, câu hỏi của tôi là:
- Có gì sai với
hung_execute
? - Tôi đoán
good_execute
hoạt động vì số>&
trong cuộc gọi open3. Nhưng tại sao và như thế nào? - Ngoài ra,
good_execute
không hoạt động khi tôi đã sử dụng các biến từ vựng (my $out
thay vìOUT
) cho tệp thủ công. Lỗi này đã xảy ra:open3: open(GLOB(0x610920), >&main::OUT) failed: Invalid argument
. Tại sao như vậy? - Dường như chỉ một trong các tay cầm tập tin có thể viết tại một thời điểm nhất định và nếu tôi loại bỏ tay cầm đang nắm giữ tài nguyên, tay kia sẽ tiếp tục chờ. Tôi từng nghĩ rằng STDERR và STDOUT là các luồng độc lập và không chia sẻ bất kỳ tài nguyên nào. Tôi đoán sự hiểu biết của tôi là một chút sai lầm ở đây. Vui lòng cho tôi một số gợi ý về điều này.
Tôi đọc trên mô-đun 'IO :: Chọn' và đã cập nhật câu hỏi của tôi ... – Unos
@Unos Bạn có rất nhiều câu hỏi. Bạn có nghĩa vụ phải hỏi chỉ một câu hỏi duy nhất. Tôi đã trả lời những cái ban đầu rồi, nhưng bạn lại hỏi những thứ tương tự như thể bạn không chú ý. Tôi đoán rằng việc trả lời tất cả các câu hỏi mới của bạn yêu cầu một đoạn hoặc ba cho gần mỗi dòng mã của bạn trong mọi chương trình. Đó là một công việc tuyệt vời để yêu cầu một người nào đó, chắc chắn hơn một giờ và hầu hết có thể xảy ra ba giờ làm việc miễn phí. Tôi không có thời gian đó hôm nay. Hãy nghiên cứu những gì tôi đã nói, bởi vì tôi không thấy nó chìm vào. – tchrist
hi @tchrist, tôi hầu như không muốn làm bạn khó chịu. Tôi đã không loại bỏ các câu hỏi trước đó của tôi sau khi cập nhật như tôi nghĩ rằng các câu trả lời có thể mất bối cảnh nếu tôi đã làm. Tôi chắc chắn sẽ nghiên cứu chi tiết hơn. – Unos