我会尽力复制这个问题,因为它非常复杂。作为概述,我有一个使用 OpenGL 显示图形的程序。这是线程特定的,所以我知道渲染只在一个线程上完成。我的另一个线程查询数据库并将数据存储在复制向量中。线程完成后,它将数据与 OpenGL 线程正在使用的数据交换(在将线程与主线程连接后)。理论上没有什么应该让程序运行这么慢?
最奇怪的部分是它最终如何“预热”并在一段时间后运行得更快(它变化很大,有时几乎是瞬间,有时在运行 30 秒后)。从价值的角度进行比较,程序在查询数据时开始以大约 30-60 fps 的速度运行(例如,不断加载它并交换它并加入线程),但是一旦它预热,它就会以 1000 fps 的速度运行.
我已经测试了一些东西,首先是让查询需要很长时间才能运行。在此期间,fps 处于最大值(3000+)。只有当数据不断变化(交换向量)时,才会开始运行得很慢。仅这一点导致性能下降是没有意义的,因为它在“热身”后运行得非常好。
编辑:
我已经设法制作了一个合理的最小可重现示例,并且我发现了一些有趣的结果。
这是代码:
#include <iostream>
#include <string>
#include <thread>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "ImGui/imgui.h"
#include "ImGui/imgui_impl_glfw.h"
#include "ImGui/imgui_impl_opengl3.h"
bool querying = false;
std::thread thread;
int m_Window_Width = 1280;
int m_Window_Height = 720;
static void LoadData()
{
querying = true;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
querying = false;
}
int main()
{
glfwInit();
const char* m_GLSL_Version = "#version 460";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
GLFWwindow* m_Window = glfwCreateWindow(m_Window_Width, m_Window_Height, "Program", NULL, NULL);
glfwMakeContextCurrent(m_Window);
glfwSwapInterval(0); // vsync
glewInit();
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGui::StyleColorsClassic();
// Setup Platform/Renderer backends
ImGui_ImplGlfw_InitForOpenGL(m_Window, true);
ImGui_ImplOpenGL3_Init(m_GLSL_Version);
thread = std::thread(LoadData);
while (!glfwWindowShouldClose(m_Window))
{
glfwPollEvents();
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
char fps[12];
sprintf_s(fps, "%f", ImGui::GetIO().Framerate);
glfwSetWindowTitle(m_Window, fps);
//Load the data
if (thread.joinable() == false && querying == false) {
thread = std::thread(LoadData);
}
//Swap the data after thread is finished
if (thread.joinable() == true && querying == false) {
thread.join();
}
// Rendering
ImGui::Render();
glfwGetFramebufferSize(m_Window, &m_Window_Width, &m_Window_Height);
glViewport(0, 0, m_Window_Width, m_Window_Height);
glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(m_Window);
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glfwDestroyWindow(m_Window);
glfwTerminate();
return 0;
}
现在有趣的是玩弄std::this_thread::sleep_for()
. 我已经实现了这个,所以我可以模拟在主数据库上运行查询时实际需要的速度。有趣的是,它实际上导致主线程停止运行并冻结它。这些线程应该是分开的并且不会相互影响,但是这里不是这种情况。对此有什么解释吗?这似乎是我的主程序的根本问题,归结为这一点。
编辑 2
要使用库(在 Visual Studio 中),请从此处下载二进制文件https://www.glfw.org/download.html以及此处http://glew.sourceforge.net/,最后ImGui
从此处下载,https://github.com/ocornut/imgui
预处理器: GLEW_STATIC; WIN32;
链接器: glfw3.lib;glew32s.lib;opengl32.lib;Gdi32.lib;Shell32.lib;user32.lib;Gdi32.lib