[JAVA] InputStreamReader performance (j2me)

Pagina: 1
Acties:

  • TheOneLLama
  • Registratie: Oktober 2000
  • Laatst online: 20-01-2022

TheOneLLama

A llama like no llama before

Topicstarter
In J2ME heb ik een programma wat een TCP verbinding opbouwdt waaraan gewoon een InputStream hangt. Uit deze InputStream wil ik vervolgens characters uitlezen en hiervoor gebruik ik dus een InputStreamReader..

Nu weet ik via available() van de InputStream hoeveel bytes er beschikbaar zijn. Het gaat hier echter om characters, en aangezien het UTF-8 is als het goed heb, kan 1 character meerdere bytes zijn.
Het probleem is dus dat ik voordat ik de read(char[]) functie van de InputStreamReader ga gebruiken ik geen idee heb hoe groot ik deze char[] moet maken!

1 Oplossing die ik kan bedenken is char[] aanmaken met de grote van het aantal bytes dat available() teruggeeft, daarmee een read(char[]) doen en vervolgens een nieuwe char[] aanmaken met de grote die read(char[]) terug geeft. En dan de gebruikte inhoud van de char[] die gebruikt is read(char[]) daarin kopieren:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// ff uit m'n hoofd dit allemaal hoop dat er geen vouten 
// in zitten :P

// in = InputStream van de socket;
InputStreamReader inr = new InputStreamReader(in);

/*
..
code die ervoor zorgt dat gewacht wordt tot er daadwerklijk data is enz.
*/

char[] acData = new char[in.available()];
int iRead = inr.read(acData);
char[] acReadData = char[iRead];

// hier komt het kopieren wat ik dus niet wil omdat het
// teveel performance kost, al je data 1 keer voor niks
// kopieren!
for (k=0; k<iRead; k++) 
  acReadData[k]=acData[k];

// acData kan nu weer vrijgemaakt worden..

als iemand een betere oplossing of effectivere manier heeft please let me know :)

Enige andere waar ik op kan komen is een eigen soort InputStreamReader maken die char[]'s teruggeeft ipv naar char[] kopieert maar dan moet ik moet UTF-8 aan de slag enz. enz. |:( misschien dat iemand dit al eens gedaan heeft of een linkje weet naar iets soortgelijks..

Opera OpenOffice.org Jabber Psi jabber://llama@mordax.com


  • Tomatrix
  • Registratie: Juni 1999
  • Laatst online: 27-02-2025
Heb er nog nooit een profiler op los gelaten maar ik doe het meestal zo:
code:
1
2
3
4
5
6
7
8
StringBuffer sb = new StringBuffer ();
BufferedReader r = new BufferedReader (new InputStreamReader (in));
char[] buf = new char [NOEM_MAAR_WAT];
int read = -1;

while ((read = r.read (buf))!= -1) {
   sb.append (buf, 0, read);
}

Vooral het gebruik van de bufferedreader is belangrijk voor de performance. Het effect van het gebruik van de stringbuffer zou ik niet weten.

edit:

En bufferedreader heeft natuurlijk ook gewoon een methode die een string teruggeeft (readLine ())

  • TheOneLLama
  • Registratie: Oktober 2000
  • Laatst online: 20-01-2022

TheOneLLama

A llama like no llama before

Topicstarter
Op maandag 11 februari 2002 01:36 schreef Tomatrix het volgende:

Heb er nog nooit een profiler op los gelaten maar ik doe het meestal zo:
code:
1
2
3
4
5
6
7
8
StringBuffer sb = new StringBuffer ();
BufferedReader r = new BufferedReader (new InputStreamReader (in));
char[] buf = new char [NOEM_MAAR_WAT];
int read = -1;

while ((read = r.read (buf))!= -1) {
   sb.append (buf, 0, read);
}

Vooral het gebruik van de bufferedreader is belangrijk voor de performance. Het effect van het gebruik van de stringbuffer zou ik niet weten.

edit:

En bufferedreader heeft natuurlijk ook gewoon een methode die een string teruggeeft (readLine ())
Bedankt voor je snelle reply :) Het gaat zoals hier erachter staat om een J2ME programma wat helaas gaan BufferedReader heeft (heb ze in J2SE wel eens gebruikt). J2ME devices zijn vaak onzettend gevoelig voor perfomance.

In het geval van dit programma gaat het om een XML-stream waar een onzettend simpele XML-parser over heen gaat. Om dit zo efficient mogelijk te doen ga ik gebruik maken van character arrays ipv strings. Het is een stream waaruit ik vaak alle beschikbare data moet halen die op dat moment verzonden(edit: in mijn programma ontvangen bedoel ik hier) is , zonder dat de stream wordt afgesloten. (zoals iedere XML-Stream hoort te werken). Er kan later weer data komen, dus wachten tot read -1 teruggeeft is er niet bij.
Dus alle beschikbare data moet ingelezen worden (bij de InputStreamReader gebeurt dit door te kijken of er data is met available() van de InputStream (op zich een overbodige stap maar dit wordt oa gebruikt om bij te houden hoeveel bytes worden ingelezen) en vervolgens met ready() van InputStreamReader te kijken of het character data is die non-blocking in te lezen is).

De XML-parser werkt door naar tags te zoeken in de ingelezen data, en de applicatie geeft zelf aan (dmv van tagnamen) welke data reeds geparsed is (geparsde data mag dus weer vrij gemaakt worden). Volgens het First In First Out principe dus eigenlijk..

Zover ik weet maakt een StringBuffer intern gebruik van een array of vector-achtig iets (wat dus uiteindelijk weer een array is) met daarin of character arrays of Strings terwijl een String slechts een enkele character array bevat. Het toevoegen van data aan een StringBuffer kan daardoor nog wel aardig effectief zijn (anders dan bij een String die compleet immutable is voor zover ik weet!) maar volgens FIFO principe weer data verwijderen uit deze buffer kan nooit goed gaan! De StringBuffer maakt dan alsnog een kopie van zichzelf als ik aan het begin van de buffer data weghaal (of niet? again, als iemand het weet..). Vandaar dat een StringBuffer ook not done is..

De manier die ik (ga) gebruik(en) is de fragmenten data die binnen komen (de J2ME implentatie zorgt ervoor dat die ook een beetje gebufferd worden gelukkig) per fragment in een aparte character array zetten. Deze characterarray-fragmenten knoop ik weer aan elkaar door ze direct in een andere array te zetten. (als dit kan.. weet ik eigenlijk niet.. kan je een array maken die (character)arrays bevat van verschillende lengtes? in ieder geval kom je zou wel vast aan een buffer met vast aantal fragmenten vrees ik, maar aan de andere kant, je geheugen gaat ook niet eeuwig door..)
Of ik zet deze in een object die weer in een Vector of in een array zit. (in eerste instantie zal ik er waarschijnlijk gewoon een Vector gebruiken, maar aangezien deze gesynchronizeerd is kan ik later als ik nog betere performance wil m'n eigen versie met arrays hiervan schrijven :))

Als alle data in een fragment geparsed is word deze simpelweg weer vrij gemaakt :) Een soort eigen StringBuffer dus maar dan met de intelligentie dat ie effectief delen vanzichzelf volgens FIFO kan vrijmaken.

Hiermee bereik ik dat alle data zodra deze binnenkomt slechts *1* keer naar het geheugen geschreven word en nergens gekopieerd word. Het is TCP/IP dus veel groter dan 1500 bytes zullen deze fragmenten niet worden (dus heel veel geheugenverlies aan dingen die al geparsed zijn maar nog in een fragment zitten waarvan andere delen nog niet geparsed zijn zal ik niet hebben).

Maar om die fragmenten van character arrays te krijgen zit ik dus nog steeds met hetzelfde probleem, hoe weet ik hoe groot ik mijn character array moet declareren??

Ik bedenk nu dat ik dit miscchien ook kan doen door m'n fragmenten als byte arrays op te slaan, en m'n XML-parser z'n characters naar bytes te laten converteren als ie de stream parsed (hoe converteer je een char[] naar een byte[]?) Of kom ik hiermee in problemen met UTF-8 encodering?

anywayz, als er iemand ideeen heeft over wat dan ook van wat ik hier geschreven heb.. laat het weten... :)

(ik ben wel op dreef zeg :D)

Opera OpenOffice.org Jabber Psi jabber://llama@mordax.com


Verwijderd

Uhm, als ik het niet verkeerd heb is iedere char gewoon hetzelfde aantal bytes(ik dacht bij java 4 bytes vanwege unicode...). Als je het aantal bytes weet kun je dus gemakkelijk een for loopje opzetten. Enigste punt is dat je er wel vanuit moet gaan dat je chars krijgt...

Greetz, daRoBBie.

  • Tomatrix
  • Registratie: Juni 1999
  • Laatst online: 27-02-2025
Wat je kan doen is 1 array declaren en vervolgens met allerlei indices gaan bijhouden van waar tot waar er geschreven mag worden, en van waar tot waar er gelezen mag worden door je parser.

Met de method read (char[] buf, int offset, int len) kan je afdwingen dat je buffer niet volloopt.

  • TheOneLLama
  • Registratie: Oktober 2000
  • Laatst online: 20-01-2022

TheOneLLama

A llama like no llama before

Topicstarter
Op maandag 11 februari 2002 09:13 schreef daRoBBie het volgende:
Uhm, als ik het niet verkeerd heb is iedere char gewoon hetzelfde aantal bytes(ik dacht bij java 4 bytes vanwege unicode...). Als je het aantal bytes weet kun je dus gemakkelijk een for loopje opzetten. Enigste punt is dat je er wel vanuit moet gaan dat je chars krijgt...

Greetz, daRoBBie.
Als ik het goed heb worden die dingen verstuurd in UTF-8.

http://prominence.com/books/net/cd/html/utf.html

dit betekend dus dat de characters variabele lengte hebben van 1 tot 3 bytes lang :(

In het systeem wat ik nu gebruik declareer ik een char[] met de lengte van het aantal bytes dat ik kan inlezen. fijn als er gewoon tekst doorheen gaat maar als iemand opeens chinees gaat lullen declareer je een array die 3 keer zo groot als nodig is!

Alles wat over de lijn gaat zijn wel gewoon UTF-8 characters..

Opera OpenOffice.org Jabber Psi jabber://llama@mordax.com


  • TheOneLLama
  • Registratie: Oktober 2000
  • Laatst online: 20-01-2022

TheOneLLama

A llama like no llama before

Topicstarter
Op maandag 11 februari 2002 10:44 schreef Tomatrix het volgende:
Wat je kan doen is 1 array declaren en vervolgens met allerlei indices gaan bijhouden van waar tot waar er geschreven mag worden, en van waar tot waar er gelezen mag worden door je parser.

Met de method read (char[] buf, int offset, int len) kan je afdwingen dat je buffer niet volloopt.
Hmm, je post brengt me wel op een idee..
Ik denk dat ik het nu als volgt ga doen.. ik ga wel gebruik maken verschillende char[]'s. Per char[] is er 1 int die bijhoud tot hoever de char[] is volgelezen (deze zitten samen in 1 object, en die objecten weer in de Vector). Ik maak die char[]'s nog steeds aan dmv te kijken hoevel bytes er beschikbaar zijn, maar als het aantal ingelezen chars (veel) verschil heeft met het aantal ingelezen bytes (dus als er nog veel plek over is in de char[]) lees ik de volgende keer (en als er weer veel plek over is ook de keer daarna etc.) de data in naar dezelfde char[] met read(char[] buf, int offset, int len)! :)

Opera OpenOffice.org Jabber Psi jabber://llama@mordax.com

Pagina: 1