Hallo,
Sinds ik een cursus Objectgeorienteerd Programmeren met Java (eerst deel 1 en nu deel 2) aan de Open Universiteit volg, vind ik het ook leuk om in mijn vrijetijd een beetje te spelen met Java. Disclaimer: overdag ben ik een .NET ontwikkelaar.
Anyways, ik heb een programma gemaakt dat de standard output van een extern proces leest (rsync) in een aparte thread en de regels daarvan doorgeeft aan de event dispatch thread, zodat ik deze regels kan weergeven in mijn Swing user interface. Dit gebeurt overigens met Java 7 met NetBeans op OS X Mavericks, hoewel dat geen invloed zou mogen hebben (vind ik, maar je weet het nooit
).
De thread wordt als volgt gestart:
Vervolgens is er een functie die de voortgang bijwerkt:
Het symptoom dat ik heb nu: de eerste paar regels worden vloeiend bijgewerkt. Zoals jullie aan de code kunnen zien heb ik er al voor gezorgd dat een Swing UI update alleen eens per 500 updates voorkomt, om de oorzaak te achterhalen.
Wat ik nu krijg, is dat het getal netjes doortelt, dus 0, 500, 1000, 1500, 2000 enzovoorts.. totdat het ergens bij de 4500 aankomt en dan houdt mijn user interface praktisch op met werken en skipt hij zo naar de 23000.
Het hoge aantal InvokeLater requests zorgt er dus voor dat Swing over zijn nek gaat, ook al voer je verder geen intensieve taken daarin uit.
Mijn vraag is nu: hoe lossen jullie Java ontwikkelaars dit op?
Bij een Google zoektocht kom ik vooral mensen tegen die roepen dat je SwingWorker moet gebruiken, maar de class die ik gemaakt heb, SyncBackup is zowel te gebruiken vanuit Swing alsook de commandline en geeft updates door via een SyncBackupObserver interface die door de caller wordt geimplementeerd. InvokeLater gebruiken in het Swing gedeelte leek mij dus de eenvoudigste en meest onafhankelijke manier om te syncen met de event dispatch thread zonder mijn SyncBackup package afhankelijk te maken van Swing.
Wel is het zo dat mijn SyncBackup class nu zelf een Thread spawnt, en dit in theorie niet per se op deze plek hoeft te gebeuren (ik zou immers met een SwingWorker misschien de thread kunnen maken ipv deze verantwoordelijkheid bij mijn SyncBackup class te leggen).
Resumerend heb ik dus een SyncBackup class die status updates aan een SyncBackupObserver doorgeeft. Mijn JFrame implementeert de SyncBackupObserver interface en krijgt dan bijvoorbeeld een backupItemProcessed door, welke weer bovenstaande updateProgress functie aanroept. Uiteraard zijn dit nogal wat events. In mijn testomgeving zijn dit er 23160
Kortom: 23160 items die ik op mijn JFrame snel voorbij wil zien komen zonder dat het traag wordt. Ik wil namelijk ook de mogelijkheid inbouwen om te kunnen annuleren tussentijds.
De updateProgress functie wordt iig goed aangeroepen, want de System.out.println(message); werkt goed en ik zie in het output window van NetBeans alle items voorbij komen die ik graag op mijn JFrame wil tonen.
Hoe zouden jullie dit oplossen?
Is het echt zo dat SwingWorker veel sneller is dan InvokeLater en moet ik de boel maar gaan ombouwen?
Of is dit onzin? Want ik lees ook berichten van mensen die zeggen dat het qua performance niet uitmaakt 
PS:
Dit is een hobby project. Ik weet dat er al 300+ rsync gui's zijn
Maar ik doe het vooral om mijn begrip van Java te verbeteren en probeer alle onderwerpen van de cursus er in te verwerken.
Sinds ik een cursus Objectgeorienteerd Programmeren met Java (eerst deel 1 en nu deel 2) aan de Open Universiteit volg, vind ik het ook leuk om in mijn vrijetijd een beetje te spelen met Java. Disclaimer: overdag ben ik een .NET ontwikkelaar.
Anyways, ik heb een programma gemaakt dat de standard output van een extern proces leest (rsync) in een aparte thread en de regels daarvan doorgeeft aan de event dispatch thread, zodat ik deze regels kan weergeven in mijn Swing user interface. Dit gebeurt overigens met Java 7 met NetBeans op OS X Mavericks, hoewel dat geen invloed zou mogen hebben (vind ik, maar je weet het nooit
De thread wordt als volgt gestart:
code:
1
2
3
4
5
6
7
8
9
10
11
12
| public void runBackupAsync()
{
Thread worker = new Thread() {
@Override
public void run() {
runBackupWork();
}
};
worker.start();
} |
Vervolgens is er een functie die de voortgang bijwerkt:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| private void updateProgress(final String message) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
itemCount++;
itemState = itemCount % 500;
if (itemState == 0)
{
lblidle.setText(itemCount + "");
}
System.out.println(message);
}
});
} |
Het symptoom dat ik heb nu: de eerste paar regels worden vloeiend bijgewerkt. Zoals jullie aan de code kunnen zien heb ik er al voor gezorgd dat een Swing UI update alleen eens per 500 updates voorkomt, om de oorzaak te achterhalen.
Wat ik nu krijg, is dat het getal netjes doortelt, dus 0, 500, 1000, 1500, 2000 enzovoorts.. totdat het ergens bij de 4500 aankomt en dan houdt mijn user interface praktisch op met werken en skipt hij zo naar de 23000.
Het hoge aantal InvokeLater requests zorgt er dus voor dat Swing over zijn nek gaat, ook al voer je verder geen intensieve taken daarin uit.
Mijn vraag is nu: hoe lossen jullie Java ontwikkelaars dit op?
Bij een Google zoektocht kom ik vooral mensen tegen die roepen dat je SwingWorker moet gebruiken, maar de class die ik gemaakt heb, SyncBackup is zowel te gebruiken vanuit Swing alsook de commandline en geeft updates door via een SyncBackupObserver interface die door de caller wordt geimplementeerd. InvokeLater gebruiken in het Swing gedeelte leek mij dus de eenvoudigste en meest onafhankelijke manier om te syncen met de event dispatch thread zonder mijn SyncBackup package afhankelijk te maken van Swing.
Wel is het zo dat mijn SyncBackup class nu zelf een Thread spawnt, en dit in theorie niet per se op deze plek hoeft te gebeuren (ik zou immers met een SwingWorker misschien de thread kunnen maken ipv deze verantwoordelijkheid bij mijn SyncBackup class te leggen).
Resumerend heb ik dus een SyncBackup class die status updates aan een SyncBackupObserver doorgeeft. Mijn JFrame implementeert de SyncBackupObserver interface en krijgt dan bijvoorbeeld een backupItemProcessed door, welke weer bovenstaande updateProgress functie aanroept. Uiteraard zijn dit nogal wat events. In mijn testomgeving zijn dit er 23160
De updateProgress functie wordt iig goed aangeroepen, want de System.out.println(message); werkt goed en ik zie in het output window van NetBeans alle items voorbij komen die ik graag op mijn JFrame wil tonen.
Hoe zouden jullie dit oplossen?
Is het echt zo dat SwingWorker veel sneller is dan InvokeLater en moet ik de boel maar gaan ombouwen?
PS:
Dit is een hobby project. Ik weet dat er al 300+ rsync gui's zijn
Ask yourself if you are happy and then you cease to be.