|
板凳

楼主 |
发表于 2009-10-15 14:51:38
|
只看该作者
poll() 应用示例
在 http://www.groad.net/bbs/read.php?tid-950.html 里,使用了非阻塞文件描述符复制文件的例子。
现在用里面的程序重新读另外一个文本文件( 6.4M 大),从输出的 errors2 文件中可以看到:[beyes@localhost poll]$ cat errors2 |grep "errno = 11" | wc -l
2191 就是在这样一个紧密循环中,失败了 2191 多次,也就是说,执行了 2191 次不必要的 write 系统调用,浪费了许多 CPU 时间。
下面通过 poll() 的测试程序来测试一下性能的提升,测试代码如下:
#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <syslog.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define BUFFER_SIZE 1000000
#define LINE_LEN 256
typedef enum {B_FALSE, B_TRUE} boolean_t; /*定义布尔变量*/
static char buf [BUFFER_SIZE];
int daemon_proc = 0;
int set_fsflag (int fd, int new_flags)
{
int flags;
if ((flags = fcntl (fd, F_GETFL)) == -1) /*得到 fd 上的状态*/
return (-1);
flags |= new_flags; /*对 fd 添加新的属性*/
if ((flags = fcntl (fd, F_SETFL, flags)) == -1) /*设置新属性*/
return (-1);
return (0);
}
int clear_fsflag (int fd, int new_flags)
{
int flags;
if ((flags = fcntl (fd, F_SETFL, flags)) == -1)
return (-1);
return (0);
}
static void err_common (boolean_t flag, int level, const char *text, va_list args)
{
int old_errno;
int n;
char buf [LINE_LEN];
old_errno = errno; /*获得错误号*/
#ifdef NEED_SNPRINTF
n = vsprintf (buf, text, args); /*n 为写入到 buf 中的字节数,不包括'\\0'*/
#else
n = vsnprintf (buf, sizeof (buf), text, args);
#endif
if (flag)
snprintf (buf + n, sizeof (buf) - n, ": %s", strerror (old_errno)); /*附加出错具体提示*/
strcat (buf, "\\n");
if (daemon_proc)
syslog (level, buf); /*产生日志消息*/
else {
fflush (stdout);
fprintf (stderr, "%s", buf);
fflush (stderr);
}
}
void log_msg (const char *text, ...)
{
va_list arg;
va_start (arg, text);
err_common (B_FALSE, LOG_INFO, text, arg);
va_end (arg);
}
void err_msg (const char *text, ...)
{
va_list arg;
va_start (arg, text);
err_common (B_TRUE, LOG_ERR, text, arg);
va_end (arg);
exit (1);
}
void err_set (const char *text, ...)
{
va_list arg;
va_start (arg, text);
err_common (B_TRUE, LOG_INFO, text, arg);
va_end (arg);
}
int main (void)
{
ssize_t n;
ssize_t res;
char *ptr;
int errs;
struct pollfd fds;
errs = 0;
n = read (STDIN_FILENO, buf, BUFFER_SIZE);
log_msg ("Read %d bytes", n);
set_fsflag (STDOUT_FILENO, O_NONBLOCK);
fds.fd = STDOUT_FILENO;
fds.events = POLLOUT;
fds.revents = 0;
ptr = buf;
while (n > 0) {
if (poll (&fds, 1, -1) == -1)
err_msg ("Can't poll");
while ((n > 0) && ((res = write (STDOUT_FILENO, ptr, n)) > 0)) {
if (errs > 0) {
err_set ("write failed %d times\\n", errs);
errs = 0;
}
log_msg ("Wrote %d bytes", res);
ptr += res;
n -= res;
}
}
clear_fsflag (STDOUT_FILENO, O_NONBLOCK);
return (0);
}
执行程序:[beyes@localhost poll]$ ./poll.exe < zypper.log 2> errors
不出错的话,输出读取到的 100,000 个字节内容。
查看生成的 errors 文件:[beyes@localhost poll]$ cat errors
Read 1000000 bytes
Wrote 4059 bytes
Wrote 4061 bytes
Wrote 4061 bytes
Wrote 4062 bytes
Wrote 4064 bytes
Wrote 4071 bytes
... ...
统计一下 errors 文件:[beyes@localhost poll]$ wc -l errors
247 errors
这里,errors 文件里的输出并不是表示是错误的提示,而是把每次写向标准输出的内容作为“出错”内容输出到标准错误中,然后导出到 errnos 文件中。从对 errors 文件的统计中可以看到,一共写了 247 次,终于写完了 100, 000 个字节。所以用 poll() 提升了不少的性能,节省了大量的 CPU 时间。 |
|