Lux.Architectuur | Van Dromen tot Wonen | www.Lux-a.nl
Dit zal je dus in aparte worker threads moeten doen. Zoek maar eens op de term swingworkers etc.
Neem je whisky mee, is het te weinig... *zucht*
Lux.Architectuur | Van Dromen tot Wonen | www.Lux-a.nl
Ik neem nu even aan dat het is om java te leren. Swingworker is wel de makkelijkste methode maar niet de mooiste in dit geval.
Care to explain?_Noldy schreef op maandag 05 oktober 2009 @ 11:08:
Ik neem nu even aan dat het is om java te leren. Swingworker is wel de makkelijkste methode maar niet de mooiste in dit geval.
Waarom zou een normale Runnable mooier zijn dan een SwingWorker?
Neem je whisky mee, is het te weinig... *zucht*
Ik was bang dat ik je het antwoord schuldig moest blijven maar dit is wat ik zojuist uit de api vis:momania schreef op maandag 05 oktober 2009 @ 11:17:
[...]
Care to explain?
Waarom zou een normale Runnable mooier zijn dan een SwingWorker?
In most cases, the Runnable interface should be used if you are only planning to override the run() method and no other Thread methods.
De klasse Swingworker bevat veel meer methodes, vaak heb je die methodes niet eens nodig. Bijvoorbeeld done().
In het geval van battler is het zo dat hij enkel iets wil toevoegen aan een TextArea. Hiervoor hoeft hij niet de alle methodes uit Swingworker te implementeren maar alleen de run() methode uit Runnable. Mede hierom is het mooier om Runnable te gebruiken i.p.v. SwingWorker.
Een SwingWorker wil je dus alleen gebruiken als je iets in een andere Thread wil doen, en het daarbij wil laten.
Wat ik niet weet is of dit ook verschil maakt bij het managen van je Thread-pool.
There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.
Je eigen tweaker.me redirect
Over mij
Met de Swingworkers is dat allemaal al voor je afgehandeld en wordt de thread in de workers executor service gegooid.
Ligt er maar net aan of je de updates in de gui direct wilt zien natuurlijk. In dit simpele voorbeeld lijkt me jouw voorstel (processen, verzamelen, gui updaten) ook beter omdat dat gewoon vele malen sneller isRobIII schreef op maandag 05 oktober 2009 @ 17:49:
Ik begeef me even op vreemd vlak want ik ben niet echt thuis in Java, maar is 't niet veel handiger om een StringBuilder (-achtig) iets te gebruiken, een string te vullen en dan gewoon pas de textarea te vullen met de inhoud van die stringbuilder?
Maar dan evengoed nog wel in een aparte thread anders blokkeert de gui alsnog tot dit klaar is.
[ Voor 58% gewijzigd door momania op 05-10-2009 18:02 ]
Neem je whisky mee, is het te weinig... *zucht*
Het is gewoon dat ik niet weet of 't zich loont om 't in een aparte thread te gooien. Ik heb even in C# gebenched met wat C# en windows specifieke (\n -> \r\n) aanpassingen:momania schreef op maandag 05 oktober 2009 @ 17:59:
Ligt er maar net aan of je de updates in de gui direct wilt zien natuurlijk. In dit simpele voorbeeld lijkt me jouw voorstel (processen, verzamelen, gui updaten) ook beter omdat dat gewoon vele malen sneller is
Maar dan evengoed nog wel in een aparte thread anders blokkeert de gui alsnog tot dit klaar is.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| using System; using System.Text; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); DateTime s = DateTime.Now; StringBuilder sb = new StringBuilder(); for (int i = 1; i < 99999; i++) sb.AppendLine(i.ToString()); textBox1.Text = sb.ToString(); Console.WriteLine(DateTime.Now - s); s = DateTime.Now; for (int i = 1; i < 99999; i++) textBox2.Text += i.ToString() + "\r\n"; Console.WriteLine(DateTime.Now - s); } } } |
Zoals je ziet zoveel mogelijk equivalent gehouden met de code uit TS.
Output:
00:00:00.0290016 00:01:07.2508466
Een slordige 2300 keer zo snel
Vandaar dat ik 't gedoe met aparte threads niet helemaal zie. Maar again; dit is C#, ik weet niet wat deze bench in Java zou doen. Als mijn GUI 0.02 seconden blokkeert... tjah. Boeie
[ Voor 4% gewijzigd door RobIII op 05-10-2009 18:20 ]
There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.
Je eigen tweaker.me redirect
Over mij
het moet in een aparte thread omdat anders al de updates in een keer achteraf komen, nadat het 'echte' rekenwerk al gedaan is.
Feit is inderdaad dat ook in Java een StringBuffer veel sneller is dan String, maar om de updates 'tussendoor' te krijgen (wat hier de hoofdvraag is van de TS) _moet_ er in Swing een aparte thread gebruikt worden.
De makkelijkste manier om hyprocrieten boos te krijgen? Confronteer ze met hun eigen uitspraken...
Eensch als je de updates tussendoor wil zien, maar a) zie ik er het nut niet van en b) haal ik dat nergens expliciet uit wat de TS zegt her-of-der.roeleboel schreef op maandag 05 oktober 2009 @ 18:19:
maar om de updates 'tussendoor' te krijgen (wat hier de hoofdvraag is van de TS) _moet_ er in Swing een aparte thread gebruikt worden.
Daar haal ik uit dat 't 4 seconden niets is en dan alles in 1 keer (wat overigens nog gunstig is in zijn geval, anders had een een crapload langer geduurdbattler schreef op zondag 04 oktober 2009 @ 12:11:
Dus ik krijg eerst 80% CPU load en niets te zien, en na een sec. of 4 verschijnt in 1 keer alles in de TextArea. Het is toch de bedoeling dat dit gewoon netjes regel voor regel wordt uitgevoerd en toegevoegd?
[ Voor 52% gewijzigd door RobIII op 05-10-2009 18:27 ]
There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.
Je eigen tweaker.me redirect
Over mij
Toch moet je het in java in een aparte thread doen, ook al wil je je resultaat in 1 keer zien. Punt is nml. dat de default thread waarin je code uitvoert de main thread is en je dus elke andere gui update blokkeert.RobIII schreef op maandag 05 oktober 2009 @ 18:23:
[...]
Eensch als je de updates tussendoor wil zien, maar a) zie ik er het nut niet van en b) haal ik dat nergens expliciet uit wat de TS zegt her-of-der.
Het mooiste blijft dan nog om het in Swingworkers te doen. De 'doInBackground' voert je code dan uit in een aparte threadpool. Wil je daarna gui updates doen, stop je die code in de 'done' methode en dat wordt dan weer in een andere aparte threadpool uitgevoerd. Zo zullen je gui updates iig niet ge-queued/vertraagd worden door background processen die (nog) niets met de gui te maken hebben
roeleboel schreef op maandag 05 oktober 2009 @ 18:19:
@Robill:
Feit is inderdaad dat ook in Java een StringBuffer veel sneller is dan String,
En heb je geen thread-safety nodig, dan is de StringBuilder (vanaf jdk 5) nog sneller
[ Voor 42% gewijzigd door momania op 05-10-2009 19:08 ]
Neem je whisky mee, is het te weinig... *zucht*
Ik denk dat het niet gunstig is in zijn geval. Het is te vergelijken met elk besturingssysteem. Als je alles in dezelfde thread zou doen dan zou bijvoorbeeld Windows moeten kiezen tussen het afspelen van geluid of het weergeven van je afspeelprogramma. Door middel van Threads kun je dit elkaar zo snel af laten wisselen dat je het idee krijgt dat het gelijk gaat. Natuurlijk is sinds de multi core processoren dit vanzelfsprekend mogelijk. Maar er lopen behoorlijk wat Threads op je pc door elkaar heen. Zie je proceslijst in Windows taskmanager maar ook binnen die processen en binnen programmas moet dat kunnen.RobIII schreef op maandag 05 oktober 2009 @ 18:23:
[...]
Eensch als je de updates tussendoor wil zien, maar a) zie ik er het nut niet van en b) haal ik dat nergens expliciet uit wat de TS zegt her-of-der.
[...]
Daar haal ik uit dat 't 4 seconden niets is en dan alles in 1 keer (wat overigens nog gunstig is in zijn geval, anders had een een crapload langer geduurd) maar nergens dat 'ie het per-se 1 voor 1 wil zien verschijnen. Wel lees ik uit z'n laatste zin dat 'ie verwacht dat de GUI onderwijl bijgewerkt wordt (en wellicht verwacht TS ook dat 'ie daarmee dus nog gewoon z'n GUI zou moeten/willen/kunnen gebruiken). En again; ik zie er dan het nut niet van als TS de updates wél per-se zou willen zien.
Wat? Een "freeze" van de GUI voor 0.02 seconden? Want de rest van 't systeem lijdt er niet (echt) onder als 't goed is (en zeker niet als 't maar 0.02 seconden is; het is natuurlijk andere koek als je die gein 60x per seconde gaat uitvoeren waarbij je telkens 0.02 sec. nodig hebt)_Noldy schreef op dinsdag 06 oktober 2009 @ 01:03:
Ik denk dat het niet gunstig is in zijn geval.
Euh; ik weet wat threads zijn en dat er meer dan 1 proces tegelijkertijd op je systeem actief is dankjewel_Noldy schreef op dinsdag 06 oktober 2009 @ 01:03:
Het is te vergelijken met elk besturingssysteem. Als je alles in dezelfde thread zou doen dan zou bijvoorbeeld Windows moeten kiezen tussen het afspelen van geluid of het weergeven van je afspeelprogramma. Door middel van Threads kun je dit elkaar zo snel af laten wisselen dat je het idee krijgt dat het gelijk gaat. Natuurlijk is sinds de multi core processoren dit vanzelfsprekend mogelijk. Maar er lopen behoorlijk wat Threads op je pc door elkaar heen. Zie je proceslijst in Windows taskmanager maar ook binnen die processen en binnen programmas moet dat kunnen.
[ Voor 15% gewijzigd door RobIII op 06-10-2009 01:46 ]
There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.
Je eigen tweaker.me redirect
Over mij
For the record:RobIII schreef op maandag 05 oktober 2009 @ 18:11:
[...]
Zoals je ziet zoveel mogelijk equivalent gehouden met de code uit TS.
Output:
00:00:00.0290016 00:01:07.2508466
Een slordige 2300 keer zo snel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| String lineSeparator = "\r\n"; JTextArea area = new JTextArea(); StringBuilder builder = new StringBuilder(); long start = System.currentTimeMillis(); for (int i=0; i<99999; i++) { builder.append(i).append(lineSeparator); } area.setText(builder.toString()); System.out.println("builder: "+ (System.currentTimeMillis() - start) + "ms"); start = System.currentTimeMillis(); for (int i=0; i<99999; i++) { area.append(String.valueOf(i)); area.append(lineSeparator); } System.out.println("textarea: "+ (System.currentTimeMillis() - start) + "ms"); |
Output:
builder: 313ms textarea: 1187ms
Wist niet dat textboxen in C# zo sloom zijn
Neem je whisky mee, is het te weinig... *zucht*
Of Stringbuilders in Java zo sloommomania schreef op dinsdag 06 oktober 2009 @ 09:31:
[...]
Output:
builder: 313ms textarea: 1187ms
Wist niet dat textboxen in C# zo sloom zijn
“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”
Zonder de line separator, die Rob vergeten is, is het al iets sneller: 78ms
Neem je whisky mee, is het te weinig... *zucht*
Rob doet ook een AppendLine, dus een line seperator is niet nodigmomania schreef op dinsdag 06 oktober 2009 @ 09:47:
[...]
Zonder de line separator, die Rob vergeten is, is het al iets sneller: 78ms
“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”
Neem je whisky mee, is het te weinig... *zucht*
Dat was inderdaad ook iets wat ik me afvroeg. In veel GUI frameworks mag je inderdaad geen wijzigingen op de GUI elementen maken op een andere thread dan de GUI thread. Nu weet ik niet hoe dat in Swing zit, maar grote kans dat je daar ook rekening mee moet houden.roy-t schreef op dinsdag 06 oktober 2009 @ 10:46:
Krijg je niet allemaal crossthread exceptions als je een swingworker gebruikt om de text te updaten? Of wordt dit uiteindelijk toch nog per regel geinvoked op het main thread? (Nog niet gezien dat iemand een swingworker gemaakt heeft, dus deze er even tussendoor).
“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”
There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.
Je eigen tweaker.me redirect
Over mij
Nope, die crossthread exceptions (ofwel: concurrent modification exceptions) krijg je niet als je de swingworkers correct gebruikt.roy-t schreef op dinsdag 06 oktober 2009 @ 10:46:
Krijg je niet allemaal crossthread exceptions als je een swingworker gebruikt om de text te updaten? Of wordt dit uiteindelijk toch nog per regel geinvoked op het main thread? (Nog niet gezien dat iemand een swingworker gemaakt heeft, dus deze er even tussendoor).
De swingworker heeft 2 core methodes die je kan overriden: 'doInBackground()' en 'done()'
'doInBackground()' Wordt uitgevoerd in een managed threadpool en dat is dus de plek om je zware werk te offloaden.
Wil je gui updates doen nadat je werk klaar is, dan doe je dat via de 'done()' methode. Deze wordt uitgevoerd op de normale event dispatch thread en komt dus netjes in een queue van gui updates.
Wil je toch tijdens een background task tussendoor je gui updaten, doe je dat via 'SwingUtilities.invokeLater(Runnable doRun)'
Dat is de manier om direct iets op de event dispatcher te queuen.
Nogmaals: standaard code uitvoer in swing wordt altijd op de event dispatch thread uitgevoerd en blokkeert dus alle gui updates tot de code klaar is. (totale blokkade dus)
[ Voor 7% gewijzigd door momania op 06-10-2009 11:04 ]
Neem je whisky mee, is het te weinig... *zucht*
Je wilt het appenden op een jtextarea maar 1x doen!!! een jTextArea is enorm traag!
Dit is wat je het beste kan doen:
1
2
3
4
5
6
| StringBuffer sb = new StringBuffer(); for(int i = 1; i < 99999; i++) { sb.append(i+ "\n"); } jTextArea1.append(sb.toString()); |
Bovenstaande code gaat waanzinnig snel. Als je iedere keer een append doet op je TextArea dan is hij enorm traag. Je String moet namelijk telkens opniew opgebouwd worden. En elke string die je toevoegd word steeds trager. Ik zit hier dus met zo'n 600-duizend tot 10 miljoen regels. Het tekenen in de jTextArea duurt langer als het creeren van de StringBuffer.
Het open van een tekstfile van 100MB en vervolgens wegschrijven in het panel duurt zo'n 15 seconden. Het telkens appenden van een string op een jTextArea bij een tekstfile van 10MB duurt een slordige 2 minuten.
Het probleem waar ik dus tegenaan loop is dat mijn GUI dus mooi een tijdje blijft hangen. (Net zoals Notepad)
Wellicht dat ik het zo laat. (Openen van de 100MB tekstfile duurt in notepad zo'n 40 seconden
Edit: Als je de StringBuffer een begingrootte heeft kun je nog wat extra performance eruit persen. Ofwel:
StringBuffer sb = new StringBuffer(18000000); //array van 18000000 tekens
Een StringBuilder is in veel gevallen trager als een StringBuffer heb ik gemerkt.
Ook moet je dit niet doen:
1
2
3
4
5
6
| String s = ""; for(int i = 1; i < 99999; i++) { s += i + "\n"; } jTextArea1.append(s); |
Dat is ook enorm traag.
[ Voor 15% gewijzigd door Twazerty op 06-10-2009 11:22 ]
Ruisende versterker: schakel je subwoofer in.
Nogal wiedes. En StringBuilders/Buffers zijn er natuurlijk niet voor nietsTwazerty schreef op dinsdag 06 oktober 2009 @ 11:18:
Ook moet je dit niet doen:
Dat is ook enorm traag.
[ Voor 66% gewijzigd door RobIII op 06-10-2009 11:25 ]
There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.
Je eigen tweaker.me redirect
Over mij
Het enigste probleem wat ik dus zie:RobIII schreef op dinsdag 06 oktober 2009 @ 11:21:
^^ En dan heeft een aparte thread dus wél nut (los van de vraag of het nuttig is om 10 miljoen regels in een textarea te mikkeren...)
Waarom zou je dat willen? Op deze manier word je input gewoon geblokked. Je weet dat je niks kunt en mag doen. Enigste reden die ik nu heb is: Een progressbar met een indicatie dat hij bezig is.
Daar had ik gisteren nog geen oplossing voor. In Threads laten lopen werd een ramp. Nu nog een Worker proberen. Kijken of ik daar verder mee kom.
Ben bezig met een uitgebreidde kladblok versie die je hele filesystem in kan lezen. C: is dan makkelijk 600-duizend regels.
Ruisende versterker: schakel je subwoofer in.
Maar waarom zou je die meuk van-voor-tot-achter in een textarea willen mikkeren? Daar zijn toch vele beter alternatieven voor? Al laad je on the fly het deel (offset) wat op dat moment in je viewport staat. Is oneindig veel sneller en met een paar regels net zo goed te maken.Twazerty schreef op dinsdag 06 oktober 2009 @ 11:27:
Ben bezig met een uitgebreidde kladblok versie die je hele filesystem in kan lezen. C: is dan makkelijk 600-duizend regels.
There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.
Je eigen tweaker.me redirect
Over mij
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
| final JTextArea textArea = new JTextArea(); final JProgressBar progressBar = new JProgressBar(); SwingWorker<String, String> worker = new SwingWorker<String, String>() { @Override protected String doInBackground() throws Exception { // background shizzle StringBuffer sb = new StringBuffer(); for (int i = 1; i < 99999; i++) { sb.append(i).append("\n"); if (i % 1000 == 0) { // publish tussentijdse updates publish(sb.toString()); // set progress van deze worker // een progress bar kan dus 'luisteren' naar updates van deze progress setProgress((int)(i*0.001)); } } return sb.toString(); } @Override protected void process(List<String> chunks) { // process the tussentijdse udpates and update gui // dit wordt ook netjes op de event dispatcher thread uitgevoerd for (String chunk : chunks) { textArea.append(chunk); } } @Override protected void done() { // klaar met processen, update the gui try { textArea.setText(get()); } catch (Exception ignore) { } } }; worker.addPropertyChangeListener(new PropertyChangeListenerProxy("progress", new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { progressBar.setValue((Integer) evt.getNewValue()); // progressbar updates hier } })); worker.execute(); |
Ja, voor sommige zaken is dit overkill, maar voor echt lang lopende background processen is dit wel de manier om het te doen.
Neem je whisky mee, is het te weinig... *zucht*
Eens. Je wil geen 600 000 regels in een textarea mikken. Dat is vragen om een hangend systeem. Met name als je het met append gaat doen. Op elk onderdeel van JTextArea etc binnen Swing heb je de paint() methode die alles voor je opnieuw gaat maken wanneer je iets wijzigt. Dus ook als je het in Threads gaat zetten moet je je afvragen of je dat echt wil.RobIII schreef op dinsdag 06 oktober 2009 @ 11:40:
[...]
Maar waarom zou je die meuk van-voor-tot-achter in een textarea willen mikkeren? Daar zijn toch vele beter alternatieven voor? Al laad je on the fly het deel (offset) wat op dat moment in je viewport staat. Is oneindig veel sneller en met een paar regels net zo goed te maken.
*offtopic: Misschien is het beter die 600 000 regels uit te printen op je printer en er een mooi boek van te maken.
600000 regels is niet de bedoeling maar wel mogelijk. Programma moet er wel tegen kunnen zeg maar. Voornamelijke doel is dat je een gedeelte van je filesystem inleest en er iets mee doet. Bv even je filmlijst in een text bestandje knikkeren. (Recursief mappen doorlopen ed) Of even een lijst maken van al je albums. (Alleen folders lezen) Een app dat vanalles kan met je files. Als mensen toch hun hele C tree in willen lezen ga ik direct naar een file schrijven. Zonder weergave. Maar 50000 regels is geen uitzondering. Bv een muziekcollectie komt daar makkelijk aan._Noldy schreef op dinsdag 06 oktober 2009 @ 13:32:
[...]
Eens. Je wil geen 600 000 regels in een textarea mikken. Dat is vragen om een hangend systeem. Met name als je het met append gaat doen. Op elk onderdeel van JTextArea etc binnen Swing heb je de paint() methode die alles voor je opnieuw gaat maken wanneer je iets wijzigt. Dus ook als je het in Threads gaat zetten moet je je afvragen of je dat echt wil.
*offtopic: Misschien is het beter die 600 000 regels uit te printen op je printer en er een mooi boek van te maken.
Alleen loop nog tegen memory problemen aan. Windows clipboard die geen 60MB plain text pakt (Vanuit java naar windows clipboard schrijven) en gewoon java VM ram problemen. Word volgens mij door jTextArea veroorzaakt. Ga nog wel allerlei oplossingen bedenken. (Max aantal regels inlezen ed) maar voor nu:
Ik doe het omdat het kan
Edit: het editen binnen een jTextArea gaat overigens wel snel ondanks dat er 1.2 miljoen regels in staan nu
[ Voor 5% gewijzigd door Twazerty op 06-10-2009 15:16 ]
Ruisende versterker: schakel je subwoofer in.
Thanks voor deze uitleg, hoop dat de TS er ook wat aan heeft. Handig dat die swingworkers dus zelf voor je invoken op het main thread (bij done).momania schreef op dinsdag 06 oktober 2009 @ 11:02:
[...]
Nope, die crossthread exceptions (ofwel: concurrent modification exceptions) krijg je niet als je de swingworkers correct gebruikt.
De swingworker heeft 2 core methodes die je kan overriden: 'doInBackground()' en 'done()'
'doInBackground()' Wordt uitgevoerd in een managed threadpool en dat is dus de plek om je zware werk te offloaden.
Wil je gui updates doen nadat je werk klaar is, dan doe je dat via de 'done()' methode. Deze wordt uitgevoerd op de normale event dispatch thread en komt dus netjes in een queue van gui updates.
Wil je toch tijdens een background task tussendoor je gui updaten, doe je dat via 'SwingUtilities.invokeLater(Runnable doRun)'
Dat is de manier om direct iets op de event dispatcher te queuen.
Nogmaals: standaard code uitvoer in swing wordt altijd op de event dispatch thread uitgevoerd en blokkeert dus alle gui updates tot de code klaar is. (totale blokkade dus)