【问题标题】:Getting Python output in real-time from C++/boost::process从 C++/boost::process 实时获取 Python 输出
【发布时间】:2021-12-27 12:18:17
【问题描述】:

从一个 C++ 程序(在 Windows 10 下运行),我使用 boost::process 调用 Python 以解释一个简单的 Python 脚本。我想将 Python 脚本的输出实时重定向到我的 C++ 程序的控制台。

我的问题是,当程序完成时,我会立即获得整个 Python 脚本输出,而不是实时获得。

这是我的 MCVE:

Python 脚本 (script.py):

import time
from datetime import datetime

print( "Started Python script at t=" + str(datetime.now().time()) )

time.sleep(1)
print( "Slept 1 sec, t=" + str(datetime.now().time()) )
time.sleep(1)
print( "Slept 1 sec, t=" + str(datetime.now().time()) )

print( "Stopped Python script at t=" + str(datetime.now().time()) )

C++ 程序(main.cpp):

#include <boost/process.hpp>
#include <ctime>
#include <iostream>
#include <chrono>

namespace bp = boost::process;

std::ostream &operator<<(std::ostream &stream, const std::chrono::system_clock::time_point& time_point) 
{
    const auto time {std::chrono::system_clock::to_time_t (time_point)};
    const auto localtime {*std::localtime (&time)};
    const auto time_since_epoch {time_point.time_since_epoch()};
    const auto milliseconds_count {std::chrono::duration_cast<std::chrono::milliseconds> (time_since_epoch).count() % 1000};
    
    stream << "[" << std::put_time (&localtime, "%T") << "." << std::setw (3) << std::setfill ('0') << milliseconds_count << "] - ";
    return stream;
}

int main( int argc, char* argv[] )
{
    std::cout << std::chrono::system_clock::now() << "Creating child" << std::endl;
    bp::ipstream stream;
    bp::child c("python.exe", "script.py", bp::std_out > stream);
    std::cout << std::chrono::system_clock::now() << "Created child" << std::endl;

    std::cout << std::chrono::system_clock::now() << "Invoking getline" << std::endl;
    std::string line;
    while (getline(stream, line)) {
        std::cout << std::chrono::system_clock::now() << "From Python output: " << line << std::endl;
    }
    std::cout << std::chrono::system_clock::now() << "getline ended" << std::endl;

    c.wait();

    return 0;
}

这个程序输出:

[12:50:34.684] - 创建子
[12:50:34.706] - 创建子
[12:50:34.708] - 调用 getline
[12:50:36.743] - 来自 Python 输出:在 t=12:50:34.742105 开始 Python 脚本
[12:50:36.745] - 来自 Python 输出:睡了 1 秒,t=12:50:35.743111
[12:50:36.745] - 来自 Python 输出:睡了 1 秒,t=12:50:36.743328
[12:50:36.746] - 来自 Python 输出:在 t=12:50:36.743328 停止 Python 脚本
[12:50:36.747] - getline 结束

如您所见,在 Python 进程结束后,我们得到了全部 4 个输出(第一次调用 getline 冻结了 2 秒 - 而 Python 运行了两个 time.sleep(1) - 然后在 3 毫秒内我们得到了全部 4 行) .我希望得到类似的东西:

[12:50:34.684] - 创建子
[12:50:34.706] - 创建子
[12:50:34.708] - 调用 getline
[12:50:34.XXX] - 来自 Python 输出:在 t=12:50:34.742105 开始 Python 脚本
[12:50:35.XXX] - 来自 Python 输出:睡眠 1 秒,t=12:50:35.743111
[12:50:36.XXX] - 来自 Python 输出:睡了 1 秒,t=12:50:36.743328
[12:50:36.XXX] - 来自 Python 输出:在 t=12:50:36.743328 停止 Python 脚本
[12:50:36.XXX] - getline 结束

我怀疑问题更多来自boost::process,而不是来自 Python,但我能找到的所有boost::process 的示例都以相同的方式读取std::cout。在 Python 打印输出时,我应该更改什么以使 getline 循环实时运行?

【问题讨论】:

  • 在python代码中你必须做print('SOME_THING', flush = True),即将flush = True添加到每个print。在 C++ 代码中,您必须添加 std::cout &lt;&lt; "SOME_THING" &lt;&lt; std::flush;,即在每次打印时将 std::flush 添加到 cout。 C++ 也可能在std::endl 输出处刷新,但这不能保证,所以最好在任何地方输出std::flush。 Python 根本不刷新,只是偶尔。在对 Python 和 C++ 代码进行这两项更改后,两个程序的代码输出将同步。
  • @Arty:没错,这就是我考虑到 Basile 的回答所做的。你是对的,Python 不会在 EOL 上刷新,只是偶尔...

标签: python c++ boost-process


【解决方案1】:

Python 流(如 C 流或 C++ 流)被缓冲(出于性能原因)。

您可能希望在 Python 代码中使用一些 flush method

您的问题可能与操作系统有关。对于 Linux,还要注意 fsync(2)termios(3)(以及 pipe(7)fifo(7)...)。对于其他操作系统,请阅读其文档。

【讨论】:

  • 您好 Basile,感谢您的帮助。我认为print 正在添加 EOL,它会自动刷新(就像在 C/C++ 中一样)。但你是对的,在 Python 脚本中添加一些 sys.stdout.flush() 或在调用 Python 时添加 -u 选项(-u 表示“强制 stdout 和 stderr 流不缓冲”)解决问题
  • @jpo38:您可能对refpersys.orgafia.asso.fr/journee-hommage-j-pitrat 上的会谈(法语)感兴趣 - 请随时通过电子邮件(法语)与我联系....(办公室:@ 987654334@在www-list.cea.fr工作;家basile@starynkevitch.net靠近巴黎)
猜你喜欢
  • 2012-02-07
  • 2018-07-21
  • 1970-01-01
  • 2017-06-23
  • 2015-06-08
  • 1970-01-01
  • 2020-03-28
  • 1970-01-01
相关资源
最近更新 更多