问题描述
我最近在论坛上问了一个问题,为什么ExecutorService在获得期货后会阻止我的程序: ExecutorService and Future are blocking the main thread
问题是经过大量调试后,罪魁祸首不是future.get(),而是int vaoID = GL30.glGenVertexArrays();
我将总结我想做的事情,然后发布代码。基本上,随着玩家的移动,我正在生成地形。为了避免游戏停滞不前,我使用了callables和ExecutorService和Futures实现了多线程。因此,当我必须生成地形时,我要向ExecutorService提交新任务(任务是计算地形的所有顶点/法线/颜色),然后对于每个将来,如果完成,我都会得到结果并生成地形模型。但是在每一帧中,完成的第一个未来都会导致冻结。实际上,造成这种情况的不是未来本身,而是模型的创建,更确切地说是int vaoID = GL30.glGenVertexArrays();
方法的创建。
总而言之,我认为glGenVertexArrays();正在阻塞该线程,等待其他线程完成,而我对发生的事情一无所知。我正在使用LWJGL 2和OpenGL 3.0 +。
以下是处理多线程的代码:
//method called each frame
private void checkForFutures(List<Future<SomeClass>> terrainsInCreation) {
try
{
List<Future<SomeClass>> futuresToRemove = new ArrayList<Future<SomeClass>>();
for(Future<SomeClass> future:terrainsInCreation) {
if(future.isDone()) {
float time = DisplayManager.getCurrentTime();
try {
SomeClass t = future.get();
Key key = new Key(t.terrain.getChunkX(),t.terrain.getChunkZ());
t.terrain.generateTerrain(loader,t.vertices,t.indices,t.colors,t.normals); // Guilty line !
futuresToRemove.add(future);
} catch (ExecutionException e) {
e.printStackTrace();
Thread.sleep(1000000);
}
}
}
terrainsInCreation.removeAll(futuresToRemove);
}
catch (InterruptedException ie)
{
System.err.println("BIG PROBLEM ON TERRAIN MANAGER");
}
}
//method called when I have terrains to generate
private void generate(List<Callable<SomeClass>> terrainsToCreate) {
for(int i = 0; i < terrainsToCreate.size();i++) {
terrainsInCreation.add(executor.submit(terrainsToCreate.get(i)));
}
}
这是generateTerrain()方法:
int vaoID = createVAO();
bindIndicesBuffer(indices);
storeDataInAttributeList(0,3,positions);
storeDataInAttributeList(1,colors);
storeDataInAttributeList(2,normals);
unbindVAO();
return new RawModel(vaoID,indices.length);
(我简化了代码)
这是createVao()方法:
private int createVAO() {
long start = DisplayManager.getCurrentTime();
int vaoID = GL30.glGenVertexArrays(); // The first of each frame takes ~40-200ms
long glGen = DisplayManager.getCurrentTime();
vaos.add(vaoID);
long add = DisplayManager.getCurrentTime();
GL30.glBindVertexArray(vaoID);
long bind = DisplayManager.getCurrentTime();
System.out.println(String.format("Vao: gen: %d + add: %d + bind: %d = %d",(glGen-start),(add-glGen),(bind-add),(DisplayManager.getCurrentTime()-start)));
return vaoID;
}
最后是常规生成的打印输出:
NEW CHECK
NEW CHECK
Vao: gen: 7 + add: 0 + bind: 0 = 7
Vao: gen: 1 + add: 0 + bind: 0 = 1
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
NEW CHECK
Vao: gen: 209 + add: 0 + bind: 0 = 209 (why????)
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 1 + add: 0 + bind: 0 = 1
Vao: gen: 1 + add: 0 + bind: 0 = 1
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 1 = 1
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
NEW CHECK
Vao: gen: 4 + add: 0 + bind: 0 = 4
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
NEW CHECK
NEW CHECK
每个帧我都在打印“ NEW CHECK”,正如您看到的那样,有时并非完全是每个帧的第一个,但是当发生世代事件时,第一个总是非常慢。
我的问题是这是怎么回事,我该怎么做/测试/更新?
感谢您的帮助。
编辑
我必须精确说明在主线程中调用了GL30.glGenVertexArrays()。 下面是在程序开始之前执行的上下文代码:
ContextAttribs attribs = new ContextAttribs(3,2)
.withForwardCompatible(true)
.withProfileCore(true);
Mouse.setGrabbed(true);
try {
DisplayMode displayMode = new DisplayMode(WIDTH,HEIGHT);
Display.setDisplayMode(displayMode);
Display.create(new PixelFormat(),attribs);
Display.setTitle("CubeLand");
} catch (LWJGLException e) {
e.printStackTrace();
}
编辑2
我通过在主线程中进行所有操作来删除了多线程,并且在生成时发生了大致相同的冻结,这是正常的,因为计算量很大,但不是GL30.glGenVertexArrays()需要任何时间进行计算。 这证明该方法正在等待所有其他线程结束,但是为什么以及如何避免这种情况呢?
NEW CHECK
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
NEW CHECK
编辑3 一些消息,当我拔出笔记本电脑的电源时,图形卡已关闭,主板图形芯片组已将其更换。突然,问题消失了。当然,由于现在性能被切断,即使使用多线程,处理器也难以生成地形,但是我仍然停滞不前,但是vao gen时间回到了0。这很令人困惑。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)