mod_rewrite documentation声明严格要求在重写程序中禁用(out)put缓冲。
记住这一点我写了一个简单的程序(我知道它缺少EOF检查,但这不是问题,它为每个循环保存了一个条件检查):
#include <stdio.h>
#include <stdlib.h>
int main ( void )
{
setvbuf(stdin,NULL,_IONBF,0);
setvbuf(stdout,NULL,_IONBF,0);
int character;
while ( 42 )
{
character = getchar();
if ( character == '-' )
{
character = '_';
}
putchar(character);
}
return 0;
}
进行一些测量后,我感到震惊 - 它比文档提供的演示Perl脚本慢了9,000倍:
#!/usr/bin/perl
$| = 1; # Turn off I/O buffering
while (<STDIN>) {
s/-/_/g; # Replace dashes with underscores
print $_;
}
现在我有两个相关的问题:
问题1。我相信这些流可能是行缓冲的,因为Apache在每条路径之后发送一个新行。我对么?将我的程序切换到
setvbuf(stdin,NULL,_IOLBF,4200);
setvbuf(stdout,NULL,_IOLBF,4200);
与Perl one一样快两次。这应该不会影响Apache的性能,不是吗?
问题2。如何在C中编写一个程序,它将使用无缓冲的流(如Perl one)并且执行速度与Perl一样快?
答案 0 :(得分:2)
问题1:您必须查看代码。它可以是行缓冲的,它可以在每个请求(或请求块)结束时使用fflush,也可以使用具有更大缓冲区的写调用。在任何情况下,它都不会执行你的程序正在进行的每字符I / O.
问题2:我怀疑主要问题是输出。如果你要将整个结果组装在缓冲区中并将其作为一个调用写出来,那么你会更快。但是,这只是意味着您正在进行行缓冲,而不是让库为您处理它。关键是没有缓冲,每个输出调用都会导致系统调用 - 这是非常高的开销。从理论上讲,相同的概念在输入中也适用,但我不确定实现是否会注意到可用的字符并在任何情况下缓冲它们。同样的解决方法 - 读取更大的缓冲区,然后自己拆开。
就个人而言,我会避免所有的setvbuf内容,并在每次请求结束时执行fflush。
答案 1 :(得分:0)
写入终端时,每行后都会刷新stdout
。这样您就可以随时看到输出。写入文件时,或者像管道一样,这个自动刷新被禁用。通常在这些情况下,表现更重要。
当进程必须相互交互时,这会导致问题。一个程序写东西。它不会立即发送,而是存储在缓冲区中。第二个程序等待该数据。第一个程序等待来自第二个程序的更多数据,导致死锁。
为避免这种情况,您需要在等待其他输入之前刷新所有输出。在每次读取操作之前,简单fflusuh(stdout)
就足够了。这实际上是$|=1
在Perl中的作用。使用stdin
无需任何操作。
如果性能至关重要且您只需要对单个字节进行操作。使用无缓冲的read / write以大块读取和写入数据。例如:
#include <unistd.h>
int main() {
char buf[1024];
while(1) {
int len = read(0,buf,sizeof(buf));
for(int i=0;i<len;i++) {
if ( buf[i] == '-' ) {
buf[i] = '_';
}
}
write(1,buf,len);
}
}