Nous avons un calcul complexe qui prend un temps variable. Avec quelques valeurs d'entrée, on peut faire mille étapes en une seconde - avec d'autres valeurs d'entrée, une étape prend plusieurs secondes.L'interface graphique prend plus de temps que le calcul et ralentit le processus entier
C'est tout à fait correct, nous voulons juste informer l'utilisateur de la progression. Le problème est que dans le premier cas, la mise à jour de l'interface graphique prend plus de temps que le calcul réel. Après cela, il reste environ 10 secondes d'événements de mise à jour dans la file d'attente (ce qui triple le temps d'exécution) .
Je pense que ce problème général, donc je l'ai cassé vers le bas un exemple agnostique un peu de cadre:
public class QueueTest {
static final int STEPS = 30;
public static void main(String[] args) {
final Gui gui = // ...
final Display display = Display.getDefault();
final Thread thread = new Thread(() -> {
for (int i = 0; i < STEPS; i++) {
final int step = i; // calculate something etc.
gui.updateLater(display, step);
}
System.out.println("Finished calculation.");
});
thread.start();
while (true) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
interface Gui {
default void updateLater(Display display, int step) {
display.asyncExec(() -> update(step));
}
default void update(int step) {
System.out.println("Update " + (step + 1) + "/" + STEPS);
if (step == STEPS - 1) {
System.out.println("Finished GUI.");
}
}
}
}
(Le Thread
supplémentaire ne « calcule » pas et l'envoie à l'interface graphique pour montrer les progrès .)
Alors considérons certaines implémentations de Gui
:
static class NoGui implements Gui {
@Override
public void update(int step) {
if (step == STEPS - 1) {
System.out.println("Finished GUI.");
}
}
}
Cet exemple s'imprime uniquement lorsque l'interface graphique est terminée. Le résultat est ces deux lignes, imprimées presque au même moment:
C'est parfaitement raisonnable. Les événements GUI sont rapides à terminer. Maintenant, nous allons les faire lentement:
static class SlowGui implements Gui {
@Override
public void update(int step) {
try {
Thread.sleep(100);
Gui.super.update(step);
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
}
Cette imprime quelque chose comme ce qui suit, avec la finition de calcul et l'interface graphique trois secondes d'intervalle:
Finished calculation.
Update 1/30
Update 2/30
Update 3/30
...
Update 30/30
Finished GUI.
C'est ce que je vois dans notre application . Le calcul se termine, mais l'interface graphique est trop lente et doit exécuter sa file d'attente d'événements une fois le calcul effectué.
Je veux optimiser ce comportement et est venu avec quelque chose comme ceci:
static class IgnorantGui extends SlowGui {
private boolean inProgress;
private Integer nextStep;
@Override
public void updateLater(Display display, int step) {
if (this.inProgress) {
this.nextStep = Integer.valueOf(step);
} else {
this.inProgress = true;
super.updateLater(display, step);
}
}
@Override
public void update(int step) {
try {
Integer currentStep = Integer.valueOf(step);
do {
super.update(currentStep.intValue());
currentStep = this.nextStep;
this.nextStep = null;
} while (currentStep != null);
} finally {
this.inProgress = false;
}
}
}
La sortie est les quatre lignes suivantes:
Finished calculation.
Update 1/30
Update 30/30
Finished GUI.
Cette mise en œuvre ne tient pas compte que les événements entre les deux et ainsi est beaucoup plus rapide. C'est une solution valide à mon problème.
Je pense que tout ce cas d'utilisation peut être commun, et peut-être qu'il existe une solution plus élégante. Ou même une API Java standard pour le gérer. (Peut-être une API SWT/Eclipse Framework, puisque c'est ce que nous utilisons.)
Alors ... comment gérer une interface graphique qui met plus de temps à mettre à jour que le calcul et donc ralentit l'application?
Je suppose que vous utilisez 'invokeLater()' pour gérer les mises à jour de l'interface graphique? – Kayaman
@Kayaman 'invokeLater()' est Swing, n'est ce pas? Nous utilisons SWT. –
Si ma mémoire est bonne, Swing a la capacité de fusionner des événements pour améliorer le débit. J'imagine que SWT a quelque chose de similaire. Votre exemple est trop abstrait. Créez un [MCVE] (https://stackoverflow.com/help/mcve) en utilisant la technologie que vous utilisez, et essayez de résoudre ce problème. – Kayaman