我正在学习perl中的非阻塞io。我有以下脚本,我试图以非阻塞方式写入文件。
这是正确的方法吗?如果不是正确的方法是什么?我在模拟一个瞬间没有发生的写入时遇到了麻烦,所以如果它起作用,我就无法测试它。
use strict;
use warnings;
use POSIX qw(:errno_h);
open(my $fh, ">>", "b.txt") or die "$! \n";
my $buffer = "aaaaaaaaaaaaaaaaaaaaaaa\n";
my $rv = syswrite($fh, $buffer, length $buffer);
#start more non blocking operations
while(1)
{
if (!defined($rv) && $! == EAGAIN) {
print "Would block \n";
} elsif ($rv != length $buffer) {
print "Incomplete write \n";
} else {
print "Successfull write so we can do what we want with the read data\n";
}
#check the other operations
#sleep for a bit
sleep 1;
}
答案 0 :(得分:4)
首先,非阻塞I / O适用于套接字和管道,但不适用于常规文件。这不是Perl的限制,而是底层系统的限制。你想要的常规文件不是非阻塞而是异步I / O:
不幸的是,对真正的异步I / O的支持是系统特定的,并且通常不受支持,所以你需要在这里使用线程(同样,这不是Perl的问题,而是底层系统的问题)。您可能需要查看IO::AIO,它试图通过使用系统支持的任何内容来让您感觉异步I / O.但请注意,它不是非常有效,如果您可以直接使用非阻塞套接字(即使用套接字但不使用常规文件),您应该这样做。
要使用非阻塞,你必须将文件描述符标记为非阻塞,然后像正常情况一样对它进行读,写,连接,接受等,除非它永远不会阻塞但返回EAGAIN
/ EWOULDBLOCK
如果操作无法立即执行。要等到文件描述符再次可读/可写,您可以使用select
,poll
,kqueue
或类似的机制。
这是一个简短的介绍。你需要注意的一些事情:
IO::Socket->blocking
为您处理主要差异。EAGAIN
与EWOULDBLOCK
相同,但在Windows上则不同,您通常使用EWOULDBLOCK
。 答案 1 :(得分:2)
我会稍微考虑一下 - 我不太熟悉这样的非阻塞IO,因为我的方法往往是thread
或fork
并且做到了办法。
非阻塞写入文件虽然并不常见 - 当使用小文件时这通常不相关,因此您的测试用例可能无法正常工作。我建议你瞄准几兆字节的写入,只是为了能够看到它发生。
至于线程方法 - 我倾向于这样做:
#!/usr/bin/perl
use strict;
use warnings;
use threads;
use Thread::Queue;
my $output_q = Thread::Queue->new();
sub writer {
open( my $output_fh, ">", "output_file.txt" ) or die $!;
while ( my $line = $output_q->dequeue ) {
print {$output_fh} $line;
}
close($output_fh) or die $!;
}
## main bit.
my $writer = threads->create( \&writer );
my $done = 0;
while ( not $done ) {
$output_q->enqueue( "a" x 1024 );
# do something else.
#repeat until $done
}
$output_q->end();
$writer->join();