【发布时间】:2021-07-14 04:51:48
【问题描述】:
我正在使用 ImGui / ImPlot,我想通过多线程 for 循环来加速它。我无法理解如何调试它,因为 ImGui 在调用 FreeWrapper 时显示错误,但我什至无法找到它的调用位置。无论如何,我做了一个最小的可重现示例来演示我的问题。如果它有点大,我很抱歉,这是我能做的最好的。
#include <GL/glew.h>
#ifndef GLFW_INCLUDE_NONE
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
#endif // GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include "ImGui/imgui.h"
#include "ImGui/implot.h"
#include "ImGui/implot_internal.h"
#include "ImGui/imgui_impl_glfw.h"
#include "ImGui/imgui_impl_opengl3.h"
#include <iostream>
#include <future>
#include <vector>
#define vecSize 5000
int main(int argc, char* argv[])
{
char fps[10];
std::vector< double > xData, yData;
std::vector< std::future<void> > futures(vecSize);
const char* glslVersion = "#version 460";
glfwInit();
// Create window with graphics context
GLFWwindow* window = glfwCreateWindow(1280, 720, "Program", NULL, NULL);
glfwMakeContextCurrent(window);
glfwSwapInterval(0); // vsync
//Initialize GLEW + ImGui
glewInit();
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImPlot::CreateContext();
// Setup Dear ImGui style
ImGui::StyleColorsLight();
// Setup Platform/Renderer backends
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init(glslVersion);
//srand(time(0));
double randMax = 100;
xData.resize(vecSize);
yData.resize(vecSize);
for (int i = 0; i < vecSize; i++) {
xData[i] = 86400 * (double)i + 852163200;
yData[i] = ((double)rand() / (double)(RAND_MAX)) * randMax;
}
while (!glfwWindowShouldClose(window))
{
//Events
glfwPollEvents();
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::Begin("Graphs");
if (ImPlot::BeginPlot("Bar Graph##Line", "Day", NULL, ImVec2(-1, 0), ImPlotFlags_NoLegend | ImPlotFlags_NoBoxSelect | ImPlotFlags_AntiAliased, ImPlotAxisFlags_Time, ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_RangeFit)) {
ImPlot::PushStyleColor(ImPlotCol_Line, ImVec4(0, 1, 0, 1));
ImPlot::PushStyleColor(ImPlotCol_Fill, ImVec4(0, 1, 0, 1));
for (int i = 0; i < xData.size(); i++) {
futures[i] = std::async(std::launch::async, ImPlot::PlotBarVolume, "Bar Graph##Line Individual", xData[i], yData[i], 1, 86400 * 0.25);
}
ImPlot::PopStyleColor();
ImPlot::PopStyleColor();
for (int i = 0; i < futures.size(); i++) {
futures[i].get();
}
ImPlot::EndPlot();
}
ImGui::End();
//Fps checker
sprintf_s(fps, "%.3f", ImGui::GetIO().Framerate);
glfwSetWindowTitle(window, fps);
// Rendering
ImGui::Render();
glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImPlot::DestroyContext();
ImGui::DestroyContext();
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
在 Visual Studio 中,要重现这一点,您需要下载并链接 GLFW 和 GLEW 的二进制文件 https://www.glfw.org/download 、 http://glew.sourceforge.net/,然后(对于预处理器设置)您需要添加 GLEW_STATIC。您还需要 ImGui 和 ImPlot,它们易于集成,https://github.com/ocornut/imguihttps://github.com/epezent/implot。另外,最后要注意的是,为了让std::async 与函数ImPlot::PlotBarVolume 一起工作,我已经修改并创建了一个新函数,它只接收数据作为对单个值的引用,而不是指向整个值的指针数组(所以它可以让我更改每个单独的颜色),但它与内置函数 ImPlot::PlotBars 完全相同。
对于手头的问题(我不知道如何解决),这里的这一行,
futures[i] = std::async(std::launch::async, ImPlot::PlotBarVolume, "Bar Graph##Line Individual", xData[i], yData[i], 1, 86400 * 0.25);
应该在每个循环的霸道“条形图”上绘制一个“条”。我想并行化它以更快地运行,但我遇到了运行时崩溃。 futures 是一个 std::vector< std::future<void> >,与 for 循环中的迭代大小相同。为什么这不起作用,我怎样才能让它达到它的状态?
【问题讨论】:
-
我不确定您是否可以在对同一图像进行操作时正确并行化它。当您绘制线条时,您可能会修改相同的位置,这就是数据竞争。此外,画线主要是一种内存访问——在大多数 PC 中,单个内核几乎可以完全利用所有内存访问。只有像服务器级处理器是不同的野兽。
-
我对 ImGUI 不太熟悉,但该错误可能是由于线程关联性造成的。基本上,只有实例化 OpenGL 的线程才有权访问它。可能有一些方法可以绕过它。
-
函数接受对向量索引的 const 引用是否有帮助?因为那样每次循环时它总是在不同的点上?
-
我已经使用 ImGui 对此进行了测试,根据我所做的,让多个线程启动某些 ImGui 绘制调用绝对可以。我不知道为什么,特别是因为我没有打电话给
glfwMakeContextCurrent,但我测试的东西仍然有效,这就是为什么我进入下一个阶段,我想将它应用到一个 for 循环,使我的程序 FPS从 2000-3000 降至 50 左右 -
你需要在所有期货返回后调用样式pop。此外,您启动了太多不好的异步操作。 5000太多了。您最多应该启动 8 个并在它们之间分配工作量。
标签: c++ multithreading parallel-processing