3

分析我的程序和函数 print 需要花费大量时间来执行。如何将“原始”字节输出直接发送到标准输出而不是使用 fwrite,并使其更快(需要同时将 print() 中的所有 9 个字节发送到标准输出)?

void print(){
    unsigned char temp[9];

    temp[0] = matrix[0][0];
    temp[1] = matrix[0][1];
    temp[2] = matrix[0][2];
    temp[3] = matrix[1][0];
    temp[4] = matrix[1][1];
    temp[5] = matrix[1][2];
    temp[6] = matrix[2][0];
    temp[7] = matrix[2][1];
    temp[8] = matrix[2][2];

    fwrite(temp,1,9,stdout);

}

Matrix 被全局定义为一个无符号字符矩阵[3][3];

4

11 回答 11

10

IO 不是一个廉价的操作。实际上,这是一个阻塞操作,这意味着当您调用write以允许更多受 CPU 限制的进程在您正在写入的 IO 设备完成操作之前运行时,操作系统可以抢占您的进程。

您可以使用的唯一较低级别的功能(如果您在 *nix 机器上开发)是使用 rawwrite功能,但即便如此,您的性能也不会比现在快得多。简单地说:IO 是昂贵的。

于 2009-02-09T15:24:07.717 回答
10

评分最高的答案声称 IO 很慢。

这是一个快速基准测试,它具有足够大的缓冲区以使操作系统脱离关键性能路径,但前提您愿意接收巨大的输出。如果第一个字节的延迟是您的问题,您需要在“dribs”模式下运行。

从 9 字节数组中写入 1000 万条记录

在 gcc 4.6.1 下 3GHz CoreDuo 上的 Mint 12 AMD64

   340ms   to /dev/null 
   710ms   to 90MB output file 
 15254ms   to 90MB output file in "dribs" mode 

Clang 3.0 下 2.4GHz CoreDuo 上的 FreeBSD 9 AMD64

   450ms   to /dev/null 
   550ms   to 90MB output file on ZFS triple mirror
  1150ms   to 90MB output file on FFS system drive
 22154ms   to 90MB output file in "dribs" mode

如果你能负担得起适当的缓冲,那么 IO 就没有什么慢了。

#include <stdio.h> 
#include <assert.h> 
#include <stdlib.h>
#include <string.h>

int main (int argc, char* argv[]) 
{
    int dribs = argc > 1 && 0==strcmp (argv[1], "dribs");
    int err;
    int i; 
    enum { BigBuf = 4*1024*1024 };
    char* outbuf = malloc (BigBuf); 
    assert (outbuf != NULL); 
    err = setvbuf (stdout, outbuf, _IOFBF, BigBuf); // full line buffering 
    assert (err == 0);

    enum { ArraySize = 9 };
    char temp[ArraySize]; 
    enum { Count = 10*1000*1000 }; 

    for (i = 0; i < Count; ++i) {
        fwrite (temp, 1, ArraySize, stdout);    
        if (dribs) fflush (stdout); 
    }
    fflush (stdout);  // seems to be needed after setting own buffer
    fclose (stdout);
    if (outbuf) { free (outbuf); outbuf = NULL; }
}
于 2012-04-27T17:02:56.363 回答
3

您可以做的最原始的输出形式是可能的write系统调用,像这样

write (1, matrix, 9);

1 是标准输出的文件描述符(0 是标准输入,2 是标准错误)。您的标准输出只会与另一端(即终端或您正在输入的程序)读取它的速度一样快,这可能会相当慢。

我不是 100% 确定,但是您可以尝试在 fd 1 上设置非阻塞 IO(使用fcntl),并希望操作系统会为您缓冲它,直到它可以被另一端使用。已经有一段时间了,但我认为它是这样工作的

fcntl (1, F_SETFL, O_NONBLOCK);

虽然是 YMMV。如果我在语法上错了,请纠正我,正如我所说,已经有一段时间了。

于 2009-02-09T15:35:41.307 回答
3

也许您的问题不是 fwrite() 很慢,而是它被缓冲了。尝试在 fwrite() 之后调用 fflush(stdout)。

这一切都取决于您在这种情况下对慢的定义。

于 2009-02-09T15:58:33.967 回答
1

所有打印都相当慢,尽管 iostream 的打印速度确实很慢。

您最好的选择是使用 printf,类似于:

printf("%c%c%c%c%c%c%c%c%c\n", matrix[0][0], matrix[0][1], matrix[0][2], matrix[1][0],
  matrix[1][1], matrix[1][2], matrix[2][0], matrix[2][1], matrix[2][2]);
于 2009-02-09T15:23:45.547 回答
1

正如每个人都指出,紧密内循环中的 IO 是昂贵的。当需要调试它时,我通常会根据一些标准对 Matrix 进行条件计算。

如果您的应用程序是控制台应用程序,则尝试将其重定向到文件,这将比进行控制台刷新快得多。例如 app.exe > matrixDump.txt

于 2009-02-09T16:14:35.427 回答
0

有什么问题:

fwrite(matrix,1,9,stdout);

一维数组和二维数组都占用相同的内存。

于 2009-02-09T15:26:06.540 回答
0

您可以简单地:

std::cout << temp;

printf更像是 C 风格。

然而,IO 操作成本高昂,因此请明智地使用它们。

于 2009-02-09T15:27:51.093 回答
0

尝试运行该程序两次。一次有输出,一次没有。您会注意到总体而言,没有 io 的那个是最快的。此外,您可以分叉进程(或创建线程),一个写入文件(stdout),一个执行操作。

于 2009-02-09T16:02:22.757 回答
0

所以首先,不要在每个条目上打印。基本上我要说的是不要那样做。

for(int i = 0; i<100; i++){
    printf("Your stuff");
}

而是在堆栈或堆上分配一个缓冲区,并将您的信息存储在那里,然后将这个缓冲区扔到标准输出中,就这样

char *buffer = malloc(sizeof(100));
for(int i = 100; i<100; i++){
    char[i] = 1; //your 8 byte value goes here
}

//once you are done print it to a ocnsole with 
write(1, buffer, 100); 

但在你的情况下,只需使用write(1, temp, 9);

于 2020-04-04T15:43:45.300 回答
0

我很确定您可以通过增加缓冲区大小来提高输出性能。所以你有更少的 fwrite 调用。写可能会更快,但我不确定。试试这个:

❯ yes | dd of=/dev/null count=1000000 
1000000+0 records in
1000000+0 records out
512000000 bytes (512 MB, 488 MiB) copied, 2.18338 s, 234 MB/s

对比

> yes | dd of=/dev/null count=100000 bs=50KB iflag=fullblock
100000+0 records in
100000+0 records out
5000000000 bytes (5.0 GB, 4.7 GiB) copied, 2.63986 s, 1.9 GB/s

这同样适用于您的代码。最近几天的一些测试表明,可能好的缓冲区大小约为 1 << 12 (=4096) 和 1<<16 (=65535) 字节。

于 2020-05-06T08:47:35.177 回答