使用的技术 Java 1.6 SWT GUI
问题: 在运行后台任务大约60分钟后,GUI信息更新最终停止(GUI变得完全没有响应)。
问题似乎与GUI更新有关,我无法弄清楚如何解决这种情况(查看了Java并发选项等)。优化线程使用处理信息定期更新GUI中的文本框。在我的测试过程中,这个“更新”在控制台输出和数据库输出后面显着滞后 - 假设优化执行了4000个优化步骤。控制台可以报告优化步骤1900(在数据库中确认),但GUI仍然输出来自步骤700的信息。
背景信息
我正在运行机器学习优化任务,并将任务合并到SWT GUI中。根据参数,任务可能需要一个小时或更长时间才能完成。我将优化任务设计为单独的线程。 GUI允许用户按下按钮以启动优化。 GUI包括(以简化)1)任务表和2)用于在优化期间反馈的SWT文本框。每个不同的任务组完成后,任务表都会更新。 SWT文本框输出更多的常规/频繁反馈(非常类似于System.out
但是使用线程通过GUI EDI线程更新文本框)。也就是说,我相信我至少使用了三个线程:1)GUI线程,2)用于GUI更新的aSync
线程(SWT),以及3)用于优化本身的后台线程。 (我之所以提到这一点,是因为Java并发教程明确指出长时间运行的任务必须在自己的线程中运行,以避免GUI死锁和饥饿。但是,即使我认为我这样做,GUI仍然在经过长时间的优化运行后停止 - 这就是我要解决的问题。由于优化运行需要很长时间才能完成,因此GUI失速是一个主要问题 - 在实现GUI停滞之前会丢失一个多小时。)
基本程序结构: GUI类 - >为优化类
启动一个单独的线程优化类可以通过回调
更新GUI类组件(使用SWTasyncExec
)
证实:
我可以确认后台线程完全运行 - 1)后台线程更新了几个数据库表,所有表都完全更新; 2)System.out
直接从发送到Eclipse中的控制台的优化任务输出,显示优化线程完全完整地运行。
此外,在测试期间,如果我将优化集缩减到大约400步,那么GUI似乎运行正常。
相关代码: GUI CLASS-- 用于更新GUI和GUI类的代码(由优化类线程调用) -
public void setFeedback(final String workerthreadinfo, final boolean append) {
try{
Display.getDefault().asyncExec(new Runnable(){
public void run(){
if(!textfeedback.isDisposed() && textfeedback !=null){
if (append) {
textfeedback.setText(workerthreadinfo + "\n" +
textfeedback.getText()) ;
} else {
textfeedback.setText(workerthreadinfo) ;
}
}
}
});
} .....
在GUI类中实例化优化工作线程
private OptimizerWorkerThread workerthread =
new OptimizerWorkerThread(this) ;
GUI类中的代码启动优化类(作为线程)
protected void optimize() {
workerthread.go() ;
}
优化课程 - 优化线程方法“链接”到GUI(guiwindow =上面的GUI类)
// ==================================================================
// GUI Update Methods
// ==================================================================
public void updateFeedBackInfo(String update, boolean append) {
guiwindow.setFeedback(update, append) ;
}
从优化线程回调GUI的示例
//GUI Feedback
this.updateFeedBackInfo("Saving optimization run record to database ... ",
APPENDTEXT ) ; // APPENDTEXT = boolean TRUE instructing GUI textbox to append
答案 0 :(得分:1)
这听起来不像是线程问题。
如果你在GUI线程中意外运行,那么点击按钮后GUI就会死机。所以我认为我们可以排除这种情况。
您所描述的内容更像是内存负载/性能问题。我强烈建议将Visualvm与您的应用程序连接,并特别注意不断增加内存消耗。同样使用visualvm中包含的探查器可能会暗示消耗大量CPU或内存的东西。
答案 1 :(得分:1)
解决方案附录:
在此应用程序的最终测试期间,我更仔细地确定了GUI的明显来源减慢。通过GUI减速,我的意思是复制2500个文件之间的区别。缓慢的问题需要将近20分钟才能完成复制。应用此修复后,完全相同的文件复制时间不到1分钟。
问题 该副本通过工作线程处理。工作线程定期更新GUI。此更新包括ProgressBar更新和文本框更新。
文本框更新似乎是问题的根源。我想要的是一个文本框PREPENDS状态更新信息 - 例如“复制文件C:/hello.txt” - 而不是追加(在SWT中可用)。为了创建一个虚假的前置我使用(在一个单独的线程中):
textfeedback.setText(workerthreadinfo + "\n" + textfeedback.getText()) ;
这段代码似乎是缓慢的罪魁祸首 - 可能很容易理解为什么。在每个文件副本上,复制整个文本框内容,然后将新信息添加到文本框中。在复制了大约700个文件之后,这开始陷入困境(你可以看到明显的减速)并且之后继续恶化。
修复,虽然我对它不满意,但是改为使用SWT TextBox append()方法。