Knitr:将代码块输出重定向到终端

10

我想监控一些嵌入在knitr文件中的相当长的并行计算。

这些计算依赖于我编写的一个包,相关函数使用multicore包中的mclapply进行并行化。该函数使用utils包中略微修改后的txtProgressBar实现输出进度条以监视计算的进度。进度条打印到终端,并通过fifo连接在每个mclapply迭代完成时更新。

当直接从文件中调用该函数时,这很好运行,但我找不到在knitr内使其工作的方法。我尝试了相关的块选项,可以将消息和警告重定向到终端,但无法显示进度条。有人可以帮忙吗?

抱歉没有提供最小工作示例,但我不知道如何在这种情况下创建一个。

2个回答

8

由于txtProgressBar()会写入stdout,而knitr会捕获stdout中的所有内容,因此如果进度条是基于文本并且写入stdout,则目前很难显示进度条。也许我可以在内部使用evaluate::evaluate(debug = TRUE)来实现您想要的效果,但我不确定这是否适用于文本进度条。

目前我的建议是:

  • use a GUI-based progress bar like tcltk::tkProgressBar()
  • write the progress to other places, e.g. (ab)using stderr

    ```{r progress}
    pb = txtProgressBar(min = 0, max = 100, file = stderr())
    for (i in 1:100) {
      setTxtProgressBar(pb, i)
      Sys.sleep(0.05)
    }
    close(pb)
    ```
    
  • or use your function outside a code chunk, e.g. in an inline expression (such as \Sexpr{my_multicore_function()} in Rnw or `r my_cool_fun()` in Rmd), because inline evaluation does not capture stdout


感谢您的回复@Yihui,我希望您能过来!我将尝试沿着您的第一个建议进行一些尝试,第二个建议将意味着失去缓存计算的能力。除了多核问题之外,您是否知道任何监视块内进行的计算状态的方法? - Pepin_the_sleepy
1
也许你可以将进度写入其他地方,比如文件中:txtProgressBar(..., file = 'progress_temp.txt')。或者将其写入 stderr。我会更新我的答案。 - Yihui Xie
感谢StdErr()的技巧,简单易实现且效果惊人。顺便说一下,感谢knitr,这是我每天都在使用的绝妙工具。 - Pepin_the_sleepy
@Yihui 有没有办法让knitr不捕获stdout?我想运行knitr文档,但当出现问题时,我看不到任何调试消息、警告等。 - dfrankow
@YihuiXie "knitr捕获标准输出的所有内容"。据我所见,使用print(1+1)确实可以捕获到输出内容,但对于简单的1+1则不行。在这种情况下,在HTML或PDF中没有任何输出。当然,如果在Python控制台(2.7)中运行1+1,就会有输出。这是knitr的正常行为还是我做错了什么? - Fran

1
阅读了Yihui的回答中有关将进度条打印到stderr的部分后,我建议使用sink()将stdout临时重定向到stderr。
sink(stderr())

your_code()

sink()

1
当你无法控制进度条的位置时,这非常有用(例如,如果使用别人的包,如rstan)。 - Empiromancer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接