Java GUI比计算时间长,并且减慢了整个过程

Java GUI比计算时间长,并且减慢了整个过程,java,multithreading,swt,Java,Multithreading,Swt,我们有一个复杂的计算,需要可变的时间。对于某些输入值,一秒钟可以完成数千个步骤,而对于其他输入值,一个步骤需要几秒钟 这是完全正确的,所以我们只想通知用户进度。问题在于,在前一种情况下,更新GUI的时间比实际计算时间长,因此在完成后,队列中仍有大约10秒的GUI更新事件(在这种情况下,整个计算的执行时间增加了三倍) 我认为这是一个普遍的问题,所以我将其分解为一个框架不可知的示例: 公共类队列测试{ 静态最终积分步长=30; 公共静态void main(字符串[]args){ 最终Gui=/。。。

我们有一个复杂的计算,需要可变的时间。对于某些输入值,一秒钟可以完成数千个步骤,而对于其他输入值,一个步骤需要几秒钟

这是完全正确的,所以我们只想通知用户进度。问题在于,在前一种情况下,更新GUI的时间比实际计算时间长,因此在完成后,队列中仍有大约10秒的GUI更新事件(在这种情况下,整个计算的执行时间增加了三倍)

我认为这是一个普遍的问题,所以我将其分解为一个框架不可知的示例:

公共类队列测试{
静态最终积分步长=30;
公共静态void main(字符串[]args){
最终Gui=/。。。
最终显示=Display.getDefault();
最终螺纹=新螺纹(()->{
对于(int i=0;iupdate(step));
}
默认无效更新(int步骤){
System.out.println(“更新”+(步骤+1)+“/”+步骤);
如果(步骤==步骤-1){
System.out.println(“完成的GUI”);
}
}
}
}
(附加的
线程仅“计算”步骤并将其发送到GUI以显示进度。)

让我们考虑一下<代码> GUI < /代码>的实现:

静态类NoGui实现Gui{
@凌驾
公共无效更新(int步骤){
如果(步骤==步骤-1){
System.out.println(“完成的GUI”);
}
}
}
此示例仅在GUI完成时打印。结果是这两行几乎同时打印:

已完成计算。
完成图形用户界面。
这完全合理。GUI事件很快就会完成。现在让我们让他们慢下来:

静态类SlowGui实现Gui{
@凌驾
公共无效更新(int步骤){
试一试{
睡眠(100);
Gui.super.update(步骤);
}捕获(最终中断异常e){
e、 printStackTrace();
}
}
}
这将打印如下内容,计算完成后,GUI相隔三秒:

Finished calculation.
Update 1 / 30
Update 2 / 30
Update 3 / 30
...
Update 30 / 30
Finished GUI.
这就是我在应用程序中看到的。计算完成,但GUI速度太慢,必须在计算完成后执行其事件队列

我想优化这一行为,并提出如下建议:

静态类IgnorantGui扩展了SlowGui{
私有布尔进程;
私有整数nextStep;
@凌驾
公共void更新程序(显示,int-step){
如果(本程序中){
this.nextStep=Integer.valueOf(步骤);
}否则{
this.inProgress=true;
超级更新程序(显示,步骤);
}
}
@凌驾
公共无效更新(int步骤){
试一试{
整数currentStep=整数.valueOf(步长);
做{
super.update(currentStep.intValue());
currentStep=this.nextStep;
this.nextStep=null;
}while(currentStep!=null);
}最后{
this.inProgress=false;
}
}
}
输出为以下四行:

已完成计算。
更新1/30
更新30/30
完成图形用户界面。
这个实现忽略了中间的事件,因此速度要快得多。这是解决我问题的有效办法

我认为整个用例可能很常见,也许有一个更优雅的解决方案。甚至是一些标准的JavaAPI来处理它。(可能是一些SWT/Eclipse框架API,因为我们正在使用它。)


所以。。。如何处理更新时间比计算时间长的GUI,从而降低应用程序的速度?

不知道我是否正确,但您似乎在不断更新GUI。尝试添加计数器之类的东西,确定何时更新gui。或者,如果不需要查看所有步骤,请尝试以下操作

static class SlowGui implements Gui {

@Override
public void update(int step) {
    try {
        if(step%5==0){
            Gui.super.update(step);
        }
    } catch (final InterruptedException e) {
        e.printStackTrace();
    }
}
}

这应该每5步更新一次

为什么在更新方法中有睡眠


希望我能帮助您。

不知道我是否正确,但您似乎在不断更新GUI。尝试添加计数器之类的东西,确定何时更新gui。或者,如果不需要查看所有步骤,请尝试以下操作

static class SlowGui implements Gui {

@Override
public void update(int step) {
    try {
        if(step%5==0){
            Gui.super.update(step);
        }
    } catch (final InterruptedException e) {
        e.printStackTrace();
    }
}
}

这应该每5步更新一次

为什么在更新方法中有睡眠


希望我能帮助您。

我使用的一种方法是使用UI线程中可运行的计时器轮询后台线程。为此使用
Display.timerExec

display.timerExec(100, new Runnable() {
  @Override
  public void run() {

     // TODO update UI from background thread details

     // Run again
     display.timerExec(100, this);
  }
});

后台线程不执行任何
asyncExec
调用,它只维护UI线程可以访问的数据。

我使用的一种方法是使用UI线程中可运行的计时器轮询后台线程。为此使用
Display.timerExec

display.timerExec(100, new Runnable() {
  @Override
  public void run() {

     // TODO update UI from background thread details

     // Run again
     display.timerExec(100, this);
  }
});

后台线程不执行任何
asyncExec
调用,它只维护UI线程可以访问的数据。

我假设您正在使用
invokeLater()
来处理GUI更新?@Kayaman
invokeLater()
是Swing,不是吗?我们使用的是SWT。如果我的记忆正常,Swing可以合并事件以提高吞吐量。我想SWT也有类似的东西。你的例子太抽象了。使用