【问题标题】:C++ - display progress bar when using std::asyncC++ - 使用 std::async 时显示进度条
【发布时间】:2018-04-18 10:44:50
【问题描述】:

所以我正在研究光线追踪器,为了减少渲染时间,我使用 std::async 独立进行像素计算。 我使用了this 教程,一切都很好,而且我确实能够节省大约 70% 的渲染时间。

不过,有些场景需要一段时间才能渲染,我想显示某种进度条。由于我是异步基础设施的新手,我不太确定如何做到这一点。我想要某种机制来仅打印“主”线程的进度。

这里是渲染循环——注意进度条的注释行——显然不应该去那里:

Image *image = new Image(width, height);

size_t max = width * height;
size_t cores = std::thread::hardware_concurrency();
volatile atomic<size_t> count(0);
vector<future<void>> future_vector;

while (cores--)
{
    future_vector.push_back(
        std::async(launch::async, [=, &camera, &scene, &count]()
        {
            while (true)
            {
                std::size_t index = count++;
                if (index >= max)
                    break;

                GLuint i = index % width;
                GLuint j = index / width;

                Ray ray = camera.generateRay(i + .5, j - .5);
                vec3 color = recursiveRayTrace(scene, ray, maxDepth);
                image->setPixel(i, j, color);

                // THIS IS BAD
                //std::cout << "Progress: [ "<< setprecision(1) << fixed << (count / (GLfloat)max) * 100.0 << "% ] \r";
                //std::cout.flush();

            }
        }));
}

for (auto& e : future_vector) {
    e.get();
}

return image;

更新: 所以我做了一些答案的建议——这里是结果——给未来的读者。 当异步渲染时,我对几个场景的基准是 15 秒(我故意加快速度)。 当我使用互斥锁时,时间减慢到 26 秒。 (在单线程上仍然优于 1.32)。 我还积极等待其中一个工作线程,并每隔 100 英里左右更新一次进度 - 渲染时间为 16 秒。所以我对这个结果非常满意,因为印刷几乎没有减慢这个过程。

谢谢, 阿隆

【问题讨论】:

  • 使用(原子)全局变量来保存进度。异步函数对其进行更新,并在主线程中轮询该值以进行更改。当检测到更改时,主线程会显示该值(以任何感觉方式)。
  • 作为另一种选择;而不是while (true) - 做已知数量的工作;然后在完成后重新排队。这不仅可以让您在用户关闭您的应用程序时以一种很好的方式终止您的工作人员;但也会通知您一些 % 已完成。
  • @Someprogrammerdude - 如果可以请提供一些代码方案。我知道如何使用 pthreads 等执行您建议的操作,但我不确定如何执行此操作:“检测到更改时主线程显示值”。参考也将不胜感激。
  • 检测更改很容易:存储旧值(初始化为某个合适的默认值)并与当前值进行比较。如果检测到更改,请执行任何需要执行的操作,然后使旧值等于当前值。重复。而你的主线程此刻卡在等待期货准备好,什么都不做。它可以使用例如轮询期货。 wait_for 然后检查进度的变化。
  • @Someprogrammerdude 谢谢!这就是我一直在寻找的。​​span>

标签: c++ multithreading progress-bar stdasync


【解决方案1】:

使用 std::cout 时似乎需要锁,否则异步任务会输出混乱(它们都尝试同时在控制台上打印)。 但是,我建议您使用 GDIplus(似乎您在代码中使用)来打印文本,而不是显示在相当难看的控制台窗口上。

Image *image = new Image(width, height);

size_t max = width * height;
size_t cores = std::thread::hardware_concurrency();
volatile atomic<size_t> count(0);
vector<future<void>> future_vector;
mutex cout_lock;
while (cores--)
{
    future_vector.push_back(
        std::async(launch::async, [=, &camera, &scene, &count]()
        {
            while (true)
            {
                std::size_t index = count++;
                if (index >= max)
                    break;

                GLuint i = index % width;
                GLuint j = index / width;

                Ray ray = camera.generateRay(i + .5, j - .5);
                vec3 color = recursiveRayTrace(scene, ray, maxDepth);
                image->setPixel(i, j, color);

                {  //lock variable scope
                   lock_guard<mutex> lock(cout_lock)
                   std::cout << "Progress: [ "<< setprecision(1) << fixed << (count / (GLfloat)max) * 100.0 << "% ] \r";
                   std::cout.flush();
                }

            }
        }));
}

for (auto& e : future_vector) {
    e.get();
}

return image;

【讨论】:

  • 谢谢,但实际上我想避免使用互斥锁。类似于@someprogrammerdude 的建议。但我会检查这两个选项。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多