OK, si vede il motivo per cui si sta prendendo tempo, destra?
Si dispone di 1 stringhe MB, e per ogni token, la sostituzione sta iterando tramite 1 MB e si esegue una nuova copia 1 MB. Bene, non una copia esatta, poiché ogni token trovato viene sostituito con il nuovo valore del token. Ma per ogni token stai leggendo 1 MB, aggiungendo 1 MB di spazio di archiviazione e scrivendo 1 MB.
Ora, possiamo pensare a un modo migliore di farlo? Che ne dici invece di iterare la stringa 1 MB per ciascun token, ma invece di eseguirla una volta.
Prima di spostarlo, creeremo una stringa di output vuota.
Mentre percorriamo la stringa sorgente, se troviamo un token, saltiamo in avanti i caratteri token.length()
e scriviamo il token offuscato. Altrimenti procederemo al prossimo personaggio.
In sostanza, stiamo capovolgendo il processo, eseguendo il ciclo for sulla stringa lunga e in ogni punto cercando un token. Per velocizzare questo, vorremmo un loop-up rapido per i token, quindi li inseriremo in una sorta di array associativo (un set).
Vedo perché sta prendendo molto tempo, ma non sono sicuro sulla correzione. Per ogni stringa 1 MB su cui sto eseguendo sostituzioni , ho da 1 a 2 mila token che voglio sostituire.Quindi camminare carattere per carattere alla ricerca di qualsiasi di un migliaio di gettoni non sembra più veloce
In generale, ciò che prende più lungo in programmazione? Nuova memoria.
Ora, quando creiamo un StringBuffer, è probabile che venga allocata una certa quantità di spazio (diciamo 64 byte e che ogni volta che aggiungiamo più della sua capacità attuale, probabilmente raddoppia il suo spazio. copia il vecchio buffer di caratteri su quello nuovo. (È possibile che possiamo modificare il vecchio e non copiare.)
Quindi se iniziamo con 64 byte, per ottenere fino a 1 MB, assegniamo e copiamo : 64, quindi 128, quindi 256, quindi 512, quindi 1024, quindi 2048 ... lo facciamo venti volte per ottenere fino a 1 MB. E per arrivare qui, abbiamo assegnato 1 MB solo per lanciarlo
Pre-allocare, usando qualcosa di analogo alla funzione reserve()
di C++, ci permetterà almeno di farlo tutto in una volta. Ma è ancora tutto in una volta per ogni token. Almeno stai producendo una stringa temporanea 1 MB per ogni token. Se hai 2000 token, stai allocando circa 2 miliardi di byte di memoria, il tutto per finire con 1 MB. Ogni 1 MB throwaway contiene la trasformazione della stringa risultante precedente, con il token corrente applicato.
Ed è per questo che ci vuole così tanto tempo.
Ora sì, decidere quale token applicare (se presente), ad ogni carattere, richiede anche del tempo. Potresti voler usare un'espressione regolare, che crea internamente una macchina a stati per scorrere tutte le possibilità, piuttosto che una ricerca set, come ho suggerito inizialmente. Ma quello che ti sta veramente uccidendo è il tempo di allocare tutta quella memoria, per 2000 copie di una stringa 1 MB.
Dan Gibson suggerisce:
Ordinare i gettoni in modo da non devono look per mille gettoni ogni personaggio . L'ordinamento richiederebbe un po 'di tempo per , ma probabilmente finirebbe a essendo più veloce dato che non è necessario cercare migliaia di token ogni carattere .
Questo era il mio ragionamento dietro la loro messa in un array associativo (ad esempio, Java HashSet). Ma l'altro problema è la corrispondenza, ad es. Se un token è "a" e un altro è "an" - se ci sono dei prefissi comuni, cioè, come possiamo farlo?
Ecco dove la risposta di Keltex è utile: egli delega l'abbinamento a un Regex, che è una grande idea, come già stabilisce un Regex (partita avida) e implementa come farlo. Una volta che la partita è stata fatta, possiamo esaminare ciò che è catturato, quindi utilizzare una mappa Java (anche un array associativo) per trovare il token offuscato per quello abbinato, non offuscato.
Volevo concentrare la mia risposta sul non solo come risolvere questo problema, ma sul perché c'era un problema in primo luogo.
Dove sta accadendo la lentezza? È in da.GetObfuscatedString (token) o è con quanti token hai? –
nella sostituzione, non da.GetObfuscatedString (token). 90% del tempo impiegato è la sostituzione, il 10% nel da.GetObfuscatedString (token). –
Che aspetto hanno i token? – Keltex