[Java] Methods asynchronous laten werken?

Pagina: 1
Acties:

  • QBiT
  • Registratie: September 2001
  • Laatst online: 08-01 23:44
Woei, mijn eerste post in dit subforum :)

Ik ben op het moment bezig met het proggen van een programma dat SNMP gegevens van een aantal apparaten ophaalt, en vervolgens in een database gooit (Mysql). SNMP gedeelte werk nu
vrij goed.

Het probleem is dat, op het moment dat de SNMP waarde vernieuwt zijn, wil ik dat deze in de database gezet worden. Dit word gedaan door de klasse SNMPHandler een methode aan te laten
roepen in de klasse Aperio, die het vervolgens weer doorgeeft aan de DBHandler klasse.
:SNMPHandler
code:
1
Aperio.sensorsSNMPupdated();

:Aperio
code:
1
2
3
4
public void sensorsSNMPupdated()
{
    dbHandler.updateSensorsToDatabase(getSensorsArray());
}


Niet echt ingewikkeld, maar voor de duidelijkheid. Op het moment dat ik Aperio.sensorsSNMPupdated(); uitcommentarieer, kost het updaten van de SNMP gegevens ongeveer 15 milliseconden. Op het moment dat ik deze methode wel aanroep, kost het ongeveer 320 milliseconden. Op het moment worden er nog maar 8 SNMP waarde opgehaald. Als dit er later meer worden (moeten er toch minimaal 100 worden), word dit echt te langzaam.

Het lijkt er op dat de JVM de code gewoon van boven naar beneden uitvoert, en methoden aanroept, en wacht op een antwoord of totdat zij klaar zijn. Dit wil ik niet, want het updaten van de database duurt gewoon te lang. Wat voor mogelijke oplossingen zijn hiervoor?

Natuurlijk heb ik zelf al wat research gedaan. Ik kwam uit op de package Java.util.Concurrent. Ik ben nog een beetje aan het lezen of dit een mogelijke oplossing is, maar het lijkt me een vrij ingewikkelde oplossing. Graag hoor ik dus van jullie andere mogelijke oplossingen :)

Muchios Gracias!

btw, de meeste klasse zijn al Threads, maar ik weet niet 100% zeker hoe ik kan zien op het daadwerkelijk aparte Threads geworden zijn?

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

QBiT schreef op dinsdag 22 maart 2005 @ 13:13:
Woei, mijn eerste post in dit subforum :)
Welkom.
Het lijkt er op dat de JVM de code gewoon van boven naar beneden uitvoert, en methoden aanroept, en wacht op een antwoord of totdat zij klaar zijn. Dit wil ik niet, want het updaten van de database duurt gewoon te lang. Wat voor mogelijke oplossingen zijn hiervoor?
Idd.. een asynchrone call is dan de oplossing.
Natuurlijk heb ik zelf al wat research gedaan. Ik kwam uit op de package Java.util.Concurrent. Ik ben nog een beetje aan het lezen of dit een mogelijke oplossing is, maar het lijkt me een vrij ingewikkelde oplossing. Graag hoor ik dus van jullie andere mogelijke oplossingen :)
Hmm... oplossingen zijn er legio en je bent niet meteen iets uit de java.util.concurrent library iets nodig. Wat je zou kunnen doen is zelf een thread maken die luisterd naar een queueu waarin jij al je update taken plaatst.

Ik zou dan toch gaan voor een ThreadPoolExecutor (met 1 thread) die een BlockingQueue meekrijgt. Jij hoeft dan alleen nog maar Runnable`s aan te maken en te submitten in de ThreadPoolExecutor. De ThreadPoolExecutor zijn thread ligt te wachten op taken om uit te voeren.. en zo gauw hij er een ziet dan voert hij die uit.

Het is wel belangrijk dat je niet steeds een ThreadPoolExecutor gaat aanmaken, maar dat je deze gaat hergebruiken voor dit onderdeel van het systeem. Als jij namelijk steeds nieuwe ThreadPools (en dus ook Threads) gaat aanmaken hou jij geen controle over de hoeveelheid threads die er gelijktijdig draaien.

[ Voor 7% gewijzigd door Alarmnummer op 22-03-2005 13:50 ]


  • QBiT
  • Registratie: September 2001
  • Laatst online: 08-01 23:44
Idd.. een asynchrone call is dan de oplossing.
Klinkt simpel. Kan je een tipje van de sluier oplichten hoe dit werkt? Google is niet erg behulpzaam vandaag...

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Bla{
    
    private ThreadPoolExecutor _executor = new ThreadPoolExectur(1,1,..., new LinkedBlockingQueue());
    
    
    public void updateSensorsToDatabase(final String interessanteArgumenten){
        Runnable runnable = new Runnable(){
            public void run(){
                dbHandler.updateSensorsToDatabase(interessanteArgumenten);  
            }
        };
        
        _executor.execute(runnable);
    }
}


Dit is het idee.. moet je die interessanteArgumenten nog wel ff aanpassen.. ik weet niet welke data jij allemaal nodig bent om te updaten...

[ Voor 26% gewijzigd door Alarmnummer op 22-03-2005 14:48 ]


  • QBiT
  • Registratie: September 2001
  • Laatst online: 08-01 23:44
Sweet! _/-\o_ _/-\o_ _/-\o_

Ik ga het even uitproberen! Dank Alarmnummer. Ik zag al in je profile waarom je er zoveel verstand van hebt. Andere oplossingen zijn natuurlijk nog van harte welkom!

[ Voor 3% gewijzigd door QBiT op 22-03-2005 15:16 ]


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

QBiT schreef op dinsdag 22 maart 2005 @ 15:16:
Andere oplossingen zijn natuurlijk nog van harte welkom!
Een erg belangrijk punt is dat je wel controle blijft houden hoeveel threads er gebruikt worden om deze asynchrone calls af te handelen. Als je geen controle hebt (dus zelf maar een thread opstart zoals je hieronder kunt zien)

Java:
1
2
3
4
5
6
7
8
9
public void updateSensorToDb(final String sensor){
    Runnable r = new Runnable(){
          public void run(){
                dbhandler.updateSensorToDb(sensor);
          }
    }

    new Thread(r).start();
}


Dan kun je in de problemen komen omdat er te veel threads op hetzelfde moment worden uitgevoerd. Als jij weet dat dit niet kan voorkomen, is deze oplossing een lichter alternatief.

[ Voor 3% gewijzigd door Alarmnummer op 22-03-2005 15:27 ]


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 10-05 05:42
Begrijp ik nu goed dat je eerst alle SNMP waarden uitleest (en dat gaat snel genoeg) en daarna in een keer al die waarden in de database wil zetten (en dat duurt te lang)? In dat geval kan het waarschijnlijk uit om (het gebruik van) je database te tweaken.

De meeste databases staan bijvoorbeeld by default op autocommit, wat inhoudt dat als je voor elke meetwaarde een INSERT query doet, de database ook voor elke waarde de database moet bijwerken. Dat is inderdaad traag, omdat de server moet garanderen dat de server tussendoor consistent en up-to-date is. Al die queries in een transactie onderbrengen kan dan al wonderen doen: daardoor worden alle meetwaarden in één keer ingevoerd en is de latency per query veel lager.

Verder weet ik niet hoe je nu je inserts uitvoert; gebeurt dat in SQL? In dat geval zou een prepared query een stuk kunnen schelen, omdat dezelfde query dan niet elke keer opnieuw door de SQL parser en query planner wordt gehaald.

Persoonlijk zou ik sowieso eerst proberen uit te zoeken hoe je je code zelf efficiënter kan maken. Dingen asynchroon afhandelen is handig om de bezettingsgraad van de CPU en de I/O te verhogen (en daarmee valt wel snelheidswinst te boeken) maar als je code gewoon te traag is (en de CPU en I/O al voldoende belast worden) dan kun je nauwelijks snelheid winnen door die code te verspreiden over meerdere threads (integendeel).

[ Voor 23% gewijzigd door Soultaker op 22-03-2005 17:50 ]


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Soultaker schreef op dinsdag 22 maart 2005 @ 17:47:
Begrijp ik nu goed dat je eerst alle SNMP waarden uitleest (en dat gaat snel genoeg) en daarna in een keer al die waarden in de database wil zetten (en dat duurt te lang)? In dat geval kan het waarschijnlijk uit om (het gebruik van) je database te tweaken.
k ben op het moment bezig met het proggen van een programma dat SNMP gegevens van een aantal apparaten ophaalt, en vervolgens in een database gooit (Mysql). SNMP gedeelte werk nu
vrij goed.
Hij krijgt zijn info dus ergens anders vandaan.. Niet uit de db..
[edit]
Nu ik nog een keer je reply goed lees, zie ik ook dat je dit niet zo geintepreteerd hoeft te hebben.

[ Voor 16% gewijzigd door Alarmnummer op 22-03-2005 18:15 ]


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 10-05 05:42
Dat bedoel ik ook; eerst haal je al die waarden binnen via het netwerk (daar is SNMP tenslotte voor), die gaan in een array, en die array van meetwaarden gaan vervolgens in je database (en die laatste stap moet sneller).

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Soultaker schreef op dinsdag 22 maart 2005 @ 18:18:
Dat bedoel ik ook; eerst haal je al die waarden binnen via het netwerk (daar is SNMP tenslotte voor), die gaan in een array, en die array van meetwaarden gaan vervolgens in je database (en die laatste stap moet sneller).
Ik heb nog nooit van de kreet SNMP gehoord..

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 10-05 05:42
Ik neem aan dat het Simple Network Management Protocol bedoeld wordt; is een vrij standaard onderdeel van de wat professionelere netwerkapparatuur (switches, routers, dat soort dingen) en het wordt gebruikt om apparaten van verschillende makers op een uniforme manier te kunnen beheren.

Ik neem aan dat de topic starter van bijvoorbeeld alle switches in een bedrijf wil zien of ze operationeel zijn, hoeveel dataverkeer er overheen gaat en welke clients er aan hangen, of iets dergelijks.

  • QBiT
  • Registratie: September 2001
  • Laatst online: 08-01 23:44
Zo, jullie zijn stiekem druk aan het discussieren geweest toen ik er niet was :)

Wat Soultaker oppert lijkt me een goede aanvulling op de ThreadPoolExecutor oplossing. Ik heb basis kennis van databases, zowel Oracle als Mysql. Bij Oracle is het geloof ik standaard zo dat je zelf de boel moet committen. Maar dit wist ik iig nog niet.

Toepassen van de ThreadPoolExecutor ging wat minder vloeiend. Ik had em werkend, maar toen begon die allerlei vage errors te geven over niet toegestane toegang tot vectors (Waar ik niks aan aangepast had, en die het allang deden). Ik heb het hele idee dus maar even in de koelkast gezet.

Nu een wat smerige workaround gebruikt. :
code:
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
while (status)
        {
            try
            {
                Thread.sleep(cycleTime);
                startUpdateCycle = System.currentTimeMillis();
                startCheckSensors = System.currentTimeMillis();
                checkSensors();
                stopCheckSensors = System.currentTimeMillis();
                totalCheckSensors = stopCheckSensors - startCheckSensors;
                checkTime = 29000 - totalCheckSensors;
            }
            catch(Exception e)
            {
                System.out.println("errortje");
            }
            try
            {
                Thread.sleep(1000);
                aperio.temp();
                setUpdateDatabase(false);
                
                stopUpdateCycle = System.currentTimeMillis();
                totalUpdateCycleTime = stopUpdateCycle - startUpdateCycle;
                cycleTime = 30000 - (totalUpdateCycleTime - 3);
                log.write("info :: (TimeKeeper) :: Total update Cycle took "+totalUpdateCycleTime+" Milliseconds");
            }
            catch(Exception e)
            {
                System.out.println("errortje");
            }

Maar het werkt voorlopig. Normaals bedankt voor jullie reactie.

SNMP is inderdaad een protocol voor netwerkmonitoring zeg maar. De meeste beetje serieuze apparaten ondersteunen dit. Je kunt ermee apparaten querien om gegevens zoals uptime, ingestelde verbindingsnelheid, totaal aantal binnengekomen packets, totaal aantal uitgaande packets, etc. Erg veel.
Bedoeling van dit programma is dus om het in een database te gooien, en vervolgens uit te kunnen lezen, niet alleen door middel van grafieken, maar ook gewoon doormiddel van pagina's met daarop de uptime etc.

Toepassingsgebied is eigenlijk meer LANparties als bedrijfsnetwerken :)

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 10-05 05:42
edit:
Onderstaande post is onzin, zie Alarmnummer. :)
QBiT schreef op woensdag 23 maart 2005 @ 12:28:
Toepassen van de ThreadPoolExecutor ging wat minder vloeiend. Ik had em werkend, maar toen begon die allerlei vage errors te geven over niet toegestane toegang tot vectors (Waar ik niks aan aangepast had, en die het allang deden). Ik heb het hele idee dus maar even in de koelkast gezet.
Ik weet niet hoeveel ervaring je hebt met concurrent programming, maar dit klinkt alsof je een 'gewone' Vector (ArrayList, tegenwoordig) tegelijkertijd vanuit meerder threads gebruikt. Dat kan natuurlijk niet; je hebt wel enige vorm van locking nodig in dat geval (ofwel door het zelf te doen, ofwel door door je ArrayList te wrappen in een synchronizedList.

[ Voor 5% gewijzigd door Soultaker op 23-03-2005 14:55 ]


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Vector = volledig synchronized :)

Maar ik heb verder ook meer info nodig om te zien wat er aan de hand is. Alhoewel ik eigelijk helemaal geen zin heb om ander mans bugs op te sporen ;)

[ Voor 70% gewijzigd door Alarmnummer op 23-03-2005 14:34 ]


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 10-05 05:42
Oh hee, dat is waar ook. Dat zal het dan niet zijn.

Het is overigens wel weer een argument om eerst te kijken naar andere factoren en daarna pas multithreaded cod ete gaan schrijven: concurrent programming is moeilijk om goed te doen en moeilijk te debuggen, dus tenzij je weet waar je mee bezig bent en bovendien alle mogelijkheden om het probleem op een andere manier op te lossen gehad hebt, kun je er beter niet aan beginnen.

(Nu is het in Java nog een stukje eenvoudiger dan in bijvoorbeeld C, waar je van bugs meestal helemaal geen melding krijgt.)
Pagina: 1