s' append()
media (ammortizzato) costo è già O (1) perché cresce la matrice di una percentuale ogni volta. Man mano che la matrice diventa più grande, la crescita diventa più economica ma proporzionalmente più rara. Una fetta da 10 milioni di elementi sarà 10 volte più costosa da coltivare rispetto a una porzione da 1 milione di elementi, ma poiché la capacità aggiuntiva che stiamo allocando è proporzionale alla dimensione, sarà anche 10 volte più chiamate append(slice, item)
fino alla prossima crescita . Il costo crescente e la frequenza decrescente delle riallocazioni si annullano, lasciando costante il costo medio, cioè O (1).
La stessa idea si applica anche agli array di dimensioni dinamiche di altri linguaggi: l'implementazione di Microsoft std::vector
fa aumentare l'array del 50% ogni volta, ad esempio. Ammortizzato O (1) non significa che non si paga nulla per le allocazioni, solo che si continua a pagare con lo stesso tasso medio in cui la matrice diventa più grande.
Sul mio portatile, potrei eseguire un milione di slice = append(slice, someStaticString)
s in 77 ms. Una delle ragioni per cui è veloce, che la siritinga ha notato sotto, è che "copiare" la stringa per ingrandire l'array è in realtà solo copiare l'intestazione della stringa (una coppia puntatore/lunghezza), non copiare il contenuto. 100.000 intestazioni di stringhe sono ancora sotto 2MB da copiare, non un grosso problema rispetto alle altre quantità di dati con cui stai lavorando.
container/list
si è rivelato ~ 3 volte più lento per me in un microbenchmark; append allegato-list è anche un tempo costante, ovviamente, ma immagino che append
abbia una costante più bassa perché di solito è sufficiente scrivere su un paio di parole di memoria e non allocare una voce di elenco, ecc. Il codice di temporizzazione non funzionerà nel Parco giochi ma è possibile copiare questo a livello locale ed eseguirlo per vedere voi stessi: http://play.golang.org/p/uYyMScmOjX
ma si sta facendo una domanda più specifica qui circa un applicazione grep
-come (e grazie per fare una domanda dettagliata con il contesto). Per questo, la raccomandazione di fondo è che se stai cercando concerti di log, è probabilmente meglio evitare di buffering dell'intero output in RAM.
È possibile scrivere qualcosa per trasmettere i risultati come una singola funzione: logparser.Grep(in io.Reader, out io.Writer, patterns []regexp.Regexp)
; in alternativa è possibile effettuare out
a chan []byte
o func(match []byte) (err error)
se non si desidera che il codice che invia risultati sia troppo invisibile con il codice grep.
(On []byte
vs. string
: un []byte
sembra fare il lavoro qui ed evita []byte
< =>string
conversioni quando si fanno di I/O, quindi preferirei che non so quello che tutti voi'. stai facendo, però, e se avete bisogno string
va bene.)
Se fai mantenere la lista partita tutta in RAM, essere consapevoli del fatto che mantenere intorno a un riferimento a parte di una grande stringa o di byte fetta mantiene tutta stringa/slice di origine da raccolta di dati inutili. Quindi, se segui questa strada, allora in modo controintuitivo potresti effettivamente volere per copiare le corrispondenze per evitare di conservare tutti i dati del registro di origine nella RAM.
Dati i volumi di tb dati trattati devo limitare il numero di linee per la scansione in una sola volta (motivi dovrebbero essere evidenti: una media fuori carico di I/O, il carico sulla CPU e dell'insieme residente dimensioni, cioè impedendo grande carico picchi) quindi non devo fare lo streaming veramente. Ma quello che è più importante per me è che non capisco cosa intendi nel fatto che se overflow le righe 1M il prossimo op non sarà l'allocazione di righe 1.25M + copiando quelle 1M righe? Vedi il prossimo commento per il calcolo. – LetMeSOThat4U
In Python: a = 1; cumul = 0. Quindi 'per i in range (10): stampa 'rows% .2f cumul% .2f'% (a, cumul) ,; cumul + = a; a = a * 1.25'. Risultato: righe 1.00 cumulativo 0.00 righe 1.25 cumulativo 1.00 righe 1.56 cumulativo 2.25 righe 1.95 cumulativo 3.81 righe 2.44 cumulativo 5.77 righe 3.05 cumulativo 8.21 righe 3.81 cumulativo 11.26 righe 4.77 cumulativo 15.07 righe 5.96 cumulativo 19.84 righe 7.45 cumulativo 25.80.Quindi, se inizio con una fetta di righe da 1M e ho 8 milioni di corrispondenze che richiedono una copia di 10 volte e un totale di 25 milioni di righe copiate. Questo non è un costo molto buono rispetto a quello dell'elenco collegato. – LetMeSOThat4U
Penso che una porzione di stringhe sia internamente una porzione di puntatori alle stringhe, nel senso che estendere la porzione non copierà effettivamente le stringhe, solo i puntatori al stringhe, quindi ogni voce sarà di 4 o 8 byte (a seconda dell'architettura di sistema), quindi dovrebbe essere veloce. – siritinga