Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C:为什么fprintf(标准输出…)这么慢?_C - Fatal编程技术网

C:为什么fprintf(标准输出…)这么慢?

C:为什么fprintf(标准输出…)这么慢?,c,C,我仍然经常使用控制台输出来了解代码中发生了什么。 我知道这可能有点过时,但我也用它来“管道”标准输出 进入日志文件等 然而,事实证明,控制台的输出在某些情况下会减慢 原因。我想知道是否有人能解释为什么将fprintf()发送到控制台 窗口似乎有点阻塞 到目前为止我所做的/诊断的: 我用一种简单的方法测量时间 fprintf(stdout,“快速fprintf\n”) 需要:0.82ms(平均)。这被认为太长了,因为vsprintf_s(…)只需几微秒就可以将相同的输出写入字符串。因此,必须有一些

我仍然经常使用控制台输出来了解代码中发生了什么。 我知道这可能有点过时,但我也用它来“管道”标准输出 进入日志文件等

然而,事实证明,控制台的输出在某些情况下会减慢 原因。我想知道是否有人能解释为什么将fprintf()发送到控制台 窗口似乎有点阻塞

到目前为止我所做的/诊断的:

  • 我用一种简单的方法测量时间
    fprintf(stdout,“快速fprintf\n”)
    需要:0.82ms(平均)。这被认为太长了,因为
    vsprintf_s(…)
    只需几微秒就可以将相同的输出写入字符串。因此,必须有一些专门针对控制台的阻塞

  • 为了避免阻塞,我使用
    vsprintf_s(…)
    将输出复制到类似fifo的数据结构中。数据结构由临界截面对象保护。然后,一个单独的线程通过将排队的输出放到控制台来解封数据结构

  • 通过引入管道服务,我可以获得进一步的改进。 我的程序的输出(应该在控制台窗口中结束)如下所示:

    • vsprintf_s(…)
      将输出格式化为简单字符串
    • 字符串排队进入类似fifo的数据结构,例如链表结构。此数据结构受critical section对象保护
    • 第二个线程通过将输出字符串发送到命名管道,将数据结构出列
    • 第二个进程读取命名管道并将字符串再次放入类似fifo的数据中 结构。这是为了避免读取到控制台的阻塞输出。 读取过程在读取命名管道时速度很快,并连续监视管道缓冲区的填充级别
    • 第二个进程中的第二个线程最终通过
      fprintf(stdout,…)
      将数据结构排到控制台
  • 因此,我有两个进程,每个进程至少有两个线程,它们之间有一个命名管道,管道两侧都有类似fifo的数据结构,以避免在管道缓冲区满时阻塞

    要确保控制台输出是“非阻塞”的,需要做很多工作。但结果是 还不错。我的主程序可以在几微秒内编写复杂的fprintf(stdout…)


    也许我应该早点问:有没有其他(更简单的!)方法来实现非阻塞控制台输出?

    我认为时间问题与控制台默认为行缓冲这一事实有关。这意味着每次向其写入
    '\n'
    字符时,整个输出缓冲区都会被发送到控制台,这是一个成本相当高的操作。这是您为该行立即显示在输出中而支付的价格

    您可以通过将缓冲策略更改为完全缓冲来更改此默认行为。结果是,输出将以与缓冲区大小相等的块发送到控制台,但单个操作将更快完成

    在首次写入console之前拨打此电话:

    char buf[10000];
    setvbuf(stdout, buf, _IOFBF, sizeof(buf));
    

    个别写入的计时应该会有所改进,但输出不会立即出现在控制台中。这对于调试来说不是很有用,但是时间安排会有所改进。如果您设置了一个线程,以固定的时间间隔调用
    fflush(stdout)
    ,比如说,每秒调用一次,您应该在单个写入的性能和程序写入输出与在控制台上实际看到输出之间的延迟之间取得合理的平衡。

    我怀疑是控制台速度慢。终端仿真器往往速度较慢(因为它们的波特率是其规格的一部分)。您是否只是测量了将标准输出重定向到某个文件的时间?您可以将调试信息输出到其他
    文件
    (并使用带有大缓冲区的
    setvbuf
    ),如果你还不知道等待输出通道的时间是多少,@巴西尔:WiDOWS7,Visual C++。我确实测量了从调用fprintf()到它返回的总时间。我的猜测是:管道缓冲区很小(通常为1 4KB块),发送大量输出将导致写入程序阻塞,直到读取器从管道中吸取足够的数据。(在单CPU机器上,这将导致读写器在每个块上进行两次乒乓上下文切换)Guess-2:如果程序是多线程的,mallock(snprintf内部)中的自旋锁(如果有)将保留除一个线程外的所有线程。在所有情况下:vmstat都是您的朋友。经过测试、确认,答案很棒。我希望能有一些技巧来加速这一过程。当然,这应该使用
    sizeof buf
    而不是重复神奇常数。:)@放松当然,你是对的!这显然是我的疏忽,当你看到我做了这么愚蠢的事情时,欢迎你编辑我的答案:)非常感谢@dasblinkenlight:在缓冲区已满或执行fflush(stdout)之前,没有输出。因此,执行冲洗的附加线程是必需的。