java - ExecutorService 和 Future 正在阻塞主线程
问题描述
我正在用java开发一个游戏,我实现了一个多线程系统来执行地形生成,这是一项重复性任务(〜10-20个任务,每个需要〜10-20ms,在一帧中)。目标是:
划分任务所花费的时间,因为我不希望我的玩家在地形生成时冻结。
不要等待地形生成。例如,如果我正在移动并且我面前的地形仍在生成,我不希望主线程等到地形生成后,我希望游戏继续运行,直到未来完成并且信息是检索以渲染地形。
第一个目标达到了,地形生成比较快,但是每次生成地形时主线程都被阻塞,导致生成时卡顿。
这是我的代码:
//method called each frame
private void checkForFutures(List<Future<SomeClass>> terrainsInCreation) {
System.out.println("NEW CHECK");
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();
// Some instructions (EDIT:)
Key key = new Key(t.terrain.getChunkX(),t.terrain.getChunkZ());
t.terrain.generateTerrain(loader, t.vertices, t.indices,t.colors, t.normals); // Guilty line !
terrains.put(key, t.terrain);
terrainsToRender.add(t.terrain);
futuresToRemove.add(future);
} catch (ExecutionException e) {
e.printStackTrace();
Thread.sleep(1000000);
}
System.out.println("future done, took: " + (DisplayManager.getCurrentTime()-time));
// The first future is always taking ~ 100-200ms, which is the time it takes to generate all the terrains
// roughly divided by 4, which is the numbers of core I have
}
}
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)));
}
}
这是打印的输出:
NEW CHECK
NEW CHECK
NEW CHECK
NEW CHECK
future done, took: 165.0
future done, took: 1.0
future done, took: 1.0
future done, took: 1.0
future done, took: 1.0
future done, took: 0.0
future done, took: 1.0
future done, took: 1.0
future done, took: 1.0
future done, took: 1.0
future done, took: 2.0
future done, took: 1.0
future done, took: 0.0
future done, took: 1.0
future done, took: 0.0
future done, took: 1.0
future done, took: 1.0
future done, took: 1.0
future done, took: 2.0
future done, took: 0.0
future done, took: 1.0
future done, took: 2.0
future done, took: 2.0
future done, took: 0.0
future done, took: 0.0
NEW CHECK
NEW CHECK
NEW CHECK
NEW CHECK
正如你所看到的,我正在使用future.isDone() 方法,但是如果它找到一个完成的future,它仍然会在调用future.get() 时阻塞,证明是我在最后做的打印,它给出了一个第一个未来的时间很长,然后每个未来约 1 毫秒来检索正常行为的信息。
我的问题是如何从字面上并行执行任务,并在完成时检索结果但根本不阻塞主线程?(不应该等待未完成的期货)
编辑
我将脚本隔离在一个最小的可重现项目中并且问题消失了,有罪的行是其中之一//Some instructions
,所以首先我将这些行添加到上面的代码中,其次我将继续调查和更新帖子。
我终于隔离了冻结整个过程的一行:
int vaoID = GL30.glGenVertexArrays();
所以基本上,在获得未来之后,我调用terrain.generate
它从顶点、法线、颜色等信息创建模型。为了创建模型,我首先创建了一个 vao,创建这个 vao 的第一步是这条线,当它第一次在这个框架中创建时,它会冻结,直到所有其他期货都完成,这太疯狂了!
我不得不说我肯定迷路了,我不知道有什么可做的。
解决方案
推荐阅读
- django - 无法将关键字“用户名”解析为字段。选项有:bio、blog、description、id、image、speciality、status、user、user_id
- django - 从 Django 模板上传到模型的图像不起作用
- linux - 如何在多行列表中转换用逗号分隔的单行中的多个单词
- active-directory - Window AD 的 LDAP 查询
- css - 如何在可能的右滚动条旁边浮动元素?
- javascript - 我正在尝试使用“npx/npm create-react-app hello”命令创建一个反应应用程序,并得到了整个消息
- python - 如何在 supervisord 中捕获 Flask CLI 命令的输出并将其重定向到标准输出?
- user-interface - 添加新项目时在辅助方向上展开 wxWrapSizer
- squirrel.windows - Squirrel.Windows - 我可以根据严重程度对更新进行分类,并根据更新的严重程度决定是否更新/强制重启?
- selenium - org.openqa.selenium.remote.server.WebDriverServlet 具有硬编码的会话超时