2010-05-06 16 views
10

In un programma che sto scrivendo sto facendo un sacco di manipolazione delle stringhe. Sto cercando di aumentare le prestazioni e mi chiedo se l'utilizzo di array di caratteri mostrerà un aumento delle prestazioni decente. Eventuali suggerimenti?Java Optimization String vs Char Arrays

+0

@ThePinkPoo: la tua domanda è priva di requisiti: cosa si suppone che la stringa contenga? L'intera gamma di Unicode (nel qual caso l'utilizzo di char [] si rivelerà un grave problema poiché un Java * char * è ** TOTALLY INADEQUATE ** per rappresentare i nuovi codepoint Unicode introdotti in Unicode 3.1 e successivi)? Solo (un sottoinsieme di) ASCII? In quest'ultimo caso è possibile ri-implementare l'intera classe String supportata solo da byte e si può fare molta ottimizzazione * very * nifty. Ci sono stato, fatto ciò, elaborando centinaia di megabyte di file di testo ASCII in Java ... – SyntaxT3rr0r

risposta

7

Che tipo di manipolazione stai facendo? Puoi pubblicare un esempio di codice?

Si consiglia di dare un'occhiata a StringBuilder che implementa CharSequence per migliorare le prestazioni. Non sono sicuro di volere rotolare il tuo. StringBuilder non è thread safe btw ... se vuoi sicurezza thread look a StringBuffer.

+0

Se hai bisogno di thread-safety, c'è una possibilità non banale che dovrai fare di più che semplicemente rilasciare un 'StringBuffer'. Potresti evitare deadlock e condizioni di gara, ma i risultati probabilmente non corrisponderanno a quanto ti aspettavi. –

+0

Grazie, reimplementerò e pubblicheremo i miei risultati. – ThePinkPoo

+0

@Hank: con un aggiornamento non banale, avvolgi il tuo 'sincronizzato (thebuffer) {...}' attorno ad esso, ma non hai bisogno di quel genere di cose troppo spesso. In effetti, è per questo che è stato introdotto 'StringBuilder'; per sbarazzarsi del costo di tenere serrature a tutti quando non è necessario (cioè quasi tutto il tempo). –

2

La stringa è già implementata come un array di caratteri. Che cosa hai in programma di fare diversamente? Ad ogni modo, tra questo e il fatto che GC per oggetti effimeri sia estremamente veloce, sarei sorpreso se riuscissi a trovare un modo per aumentare le prestazioni sostituendo gli array di caratteri.

Il consiglio di Michael Borgwardt su piccoli array di caratteri e l'uso di StringBuilder e StringBuffer è molto buono. Ma per me la cosa principale è cercare di non indovinare cosa è lento: fare misurazioni, usare un profiler, ottenere alcuni fatti precisi. Perché di solito le nostre supposizioni sulla performance si rivelano sbagliate.

1

Quando si dispone di un numero molto elevato di stringhe brevi, utilizzare char[] invece può risparmiare un bel po 'di memoria, il che significa anche maggiore velocità a causa di meno errori di cache.

Ma con stringhe di grandi dimensioni, la cosa principale da evitare è evitare la copia non necessaria risultante dall'immutabilità di String. Se fai molti concatenamenti o sostituzioni, usare StringBuilder può fare una grande differenza.

+0

Michael, potresti approfondire la questione sostituendo Stringhe con char []? Char [] occupa uno spazio leggermente inferiore rispetto a un'istanza String, tuttavia char [] non viene internalizzato e per molte stringhe brevi la probabilità che alcune stringhe siano uguali e che vengano internalizzate (ovvero JVM manterrà una singola copia) è molto più alto che per poche stringhe lunghe. –

+0

@Totophil: Dipende davvero dal tipo di stringhe con cui si lavora e da ciò che si fa con esse; Se si usano rappresentazioni mutabili, l'internamento diventa irrilevante. –

+0

Michael, d'accordo, dipende davvero dalle specifiche dello scenario. E l'unico scenario che mi viene in mente è quando il software ha bisogno di fare molte manipolazioni di stringhe "in atto". Ma l'approccio non sarà di alcun aiuto nell'affrontare i costi generali delle stringhe derivanti dalla concatenazione, dalle ricerche e dai confronti. –

2

Ecco un estratto dal full source of String class da JDK 6.0:

public final class String implements java.io.Serializable, 
     Comparable<String>, CharSequence { 
     /** The value is used for character storage. */ 
     private final char value[]; 

     /** The offset is the first index of the storage that is used. */ 
     private final int offset; 

     /** The count is the number of characters in the String. */ 
     private final int count; 

Come si può vedere internamente il valore è già memorizzato come un array di caratteri. Una serie di caratteri come una struttura dati ha tutti i limiti della classe String per la maggior parte delle manipolazioni di stringhe: gli array Java non crescono, cioè ogni volta (ok, potrebbe non essere ogni volta) la stringa dovrebbe crescere di cui avresti bisogno allocare un nuovo array e copiare il contenuto.

Come suggerito in precedenza, è opportuno utilizzare StringBuilder o StringBuffer per la maggior parte delle manipolazioni di stringhe.

Infatti il ​​codice seguente:

String a = "a"; 
    a=a+"b"; 
    a=a+"c"; 

Quando viene compilato saranno convertiti automaticamente per utilizzare StringBuilder, questo può essere facilmente controllato con l'aiuto di javap.

Come regola empirica, è raramente consigliabile dedicare del tempo a migliorare le prestazioni delle classi Java principali, a meno che non siate esperti di livello mondiale sull'argomento, semplicemente perché questo codice è stato scritto dagli esperti di livello mondiale nel primo posto.

2

Hai profilato la tua domanda? Sai dove sono i colli di bottiglia? Questo è il primo passo se la performance è sub par. Bene, questo e definendo quali sono le metriche di performance accettabili.

Dopo aver profilato alcuni compiti, si avranno percentuali di tempo spesi a fare le cose. Se passi molto tempo a manipolare le stringhe, forse puoi iniziare a mettere in cache alcune di quelle manipolazioni?Stai facendo alcuni di essi ripetutamente quando li fai solo una volta sarebbe sufficiente (e poi usi di nuovo quel risultato più tardi quando è necessario)? Stai copiando le stringhe quando non ne hai bisogno? Ricorda, java.lang.String è immutabile, quindi non può essere modificato direttamente.

Ho trovato diverse volte durante l'ottimizzazione/prestazioni dei sistemi di tweaking su cui lavoro che non so da dove viene la lentezza proviene da istintivamente. Ho visto altri (e, vergognosamente, me stesso) passare giorni a ottimizzare qualcosa che non mostra alcun guadagno - perché non era il collo di bottiglia originale, ed era in realtà meno dell'1% del tempo trascorso.

Spero che questo ti aiuti a orientarti nella giusta direzione.

+0

Ho profilato e non è stato molto informativo dato che la mia complessità è piuttosto ridotta. So dal profilo che i metodi di stringa lo stavano uccidendo, anche i miei loop all'interno del codice. Quindi ho intenzione di srotolare alcuni dei loop e usare StringBuilder – ThePinkPoo

+0

@ThePinkPoo: se le operazioni String lo stanno uccidendo, la cosa migliore da fare è provare a ridurre il numero di operazioni String che stai facendo. Questo può essere fatto attraverso la memorizzazione nella cache o un comportamento simile. Ci scusiamo per il fatto che tu non abbia un profilo - lo vedo spesso su varie pagine di forum (qui incluso), e volevo assicurarmi che lo stavi facendo. :) In bocca al lupo. – aperkins