2008-09-17 12 views
5

Ich habe eine Funktion innerhalb einer Schleife innerhalb einer Funktion. Die innere Funktion erfasst und speichert einen großen Vektor von Daten im Speicher (als eine globale Variable ... Ich benutze "R", was wie "S-Plus" ist). Die Schleife durchläuft eine lange Liste von zu erfassenden Daten. Die äußere Funktion startet den Prozess und übergibt die Liste der zu erfassenden Datensätze.Schlimmere Sünde: Nebenwirkungen oder das Passieren von massiven Objekten?

for (dataset in list_of_datasets) { 
    for (datachunk in dataset) { 
    <process datachunk> 
    <store result? as vector? where?> 
    } 
} 

programmierte ich die innere Funktion jeden Datensatz zu speichern, bevor zum nächsten zu bewegen, so dass alle der Arbeit der äußeren Funktion tritt als Nebenwirkungen auf globale Variablen ... ein großen No-No. Ist das besser oder schlechter als das Sammeln und Zurückgeben eines gigantischen, speicherhungrigen Vektorvektors? Gibt es einen überlegenen dritten Ansatz?

Würde sich die Antwort ändern, wenn ich die Datenvektoren lieber in einer Datenbank als im Speicher abspeichern würde? Idealerweise möchte ich die Funktion beenden können (oder sie aufgrund von Netzwerk-Timeouts fehlschlagen lassen), ohne alle Informationen zu verlieren, die vor der Beendigung verarbeitet wurden.

+2

empfehle ich bearbeite diesen Beitrag einige kurze Pseudo-Code enthalten, so dass es einfacher ist, zu sehen, was Sie versuchen, Pseudo-Code zu tun, fügen Sie –

+0

Ja bitte Es ist unmöglich zu wissen, was du meinst. Wenn Sie sagen "Prozess ... und speichern Sie das Ergebnis", meinen Sie "speichern Sie die exakt gleiche Zeichenfolge", oder Vektor (von Ints, verweisende Wörter), oder was? Speichern Sie es als Datensatz in einem riesigen Datenrahmen/Array/Matrix? Geben Sie uns eine Vorstellung von der Anzahl der Zeilen, Spalten, Datei-, Chunk- und Vektorgrößen und Ihrem Arbeitsspeicher? – smci

Antwort

-1

Es ist schwierig, definitiv zu sagen, ohne die Sprache/den verwendeten Compiler zu kennen. Wenn Sie jedoch einfach einen Zeiger/Verweis auf das Objekt, das Sie erstellen, übergeben, hat die Größe des Objekts selbst nichts mit der Geschwindigkeit der Funktionsaufrufe zu tun. Manipulieren dieser Daten auf der Straße könnte eine andere Geschichte sein.

+1

Die Sprache, die er benutzt, ist R: http://r-project.org/ – Allen

10

Verwenden Sie Variablen in der äußeren Funktion anstelle von globalen Variablen. Dadurch erhalten Sie das Beste aus beiden Ansätzen: Sie mutieren nicht den globalen Status und Sie kopieren keinen großen Datenblock. Wenn Sie vorzeitig beenden müssen, geben Sie nur die Teilergebnisse zurück.

(Siehe „Scope“ in der R Handbuch: http://cran.r-project.org/doc/manuals/R-intro.html#Scope)

0

dritter Ansatz: innere Funktion gibt einen Verweis auf die große Anordnung, die die nächste Anweisung in der Schleife dann dereferenziert und speichert, wo es gebraucht wird (idealerweise mit einem einzelnen Zeigerspeicher und nicht durch Memcopy das gesamte Array).

Dies beseitigt sowohl die Nebenwirkung als auch die Weitergabe großer Datenstrukturen.

4

Es wird keinen großen Unterschied bei der Speichernutzung geben, also können Sie den Code auch sauber machen.

Da R copy-on-modify für Variablen hat, hat das Ändern des globalen Objekts die gleichen Auswirkungen auf den Speicher wie das Zurückgeben von Werten in Rückgabewerten.

Wenn Sie die Ausgaben in einer Datenbank (oder sogar in einer Datei) speichern, haben Sie keine Probleme mit der Speicherbelegung, und die Daten werden nicht nur am Ende, sondern bei der Erstellung schrittweise zur Verfügung gestellt. Ob es schneller mit der Datenbank ist, hängt hauptsächlich davon ab, wie viel Speicher Sie verwenden: Ist die Reduzierung, die Garbage Collection, um die Kosten für das Schreiben auf die Festplatte zu bezahlen.

Es gibt sowohl Zeit- als auch Speicherprofiler in R, so dass Sie empirisch sehen können, was die Auswirkungen sind.

1

Ich bin mir nicht sicher, ob ich die Frage verstehe, aber ich habe ein paar Lösungen.

  1. In der Funktion erstellen Sie eine Liste der Vektoren und geben Sie diese zurück.

  2. In der Funktion erstellen Sie eine Umgebung und speichern Sie alle Vektoren darin. Stellen Sie nur sicher, dass Sie die Umgebung im Falle von Fehlern zurückgeben.

in R:

help(environment) 

# You might do something like this: 

outer <- function(datasets) { 
    # create the return environment 
    ret.env <- new.env() 
    for(set in dataset) { 
    tmp <- inner(set) 
    # check for errors however you like here. You might have inner return a list, and 
    # have the list contain an error component 
    assign(set, tmp, envir=ret.env) 
    } 
    return(ret.env) 
} 

#The inner function might be defined like this 

inner <- function(dataset) { 
    # I don't know what you are doing here, but lets pretend you are reading a data file 
    # that is named by dataset 
    filedata <- read.table(dataset, header=T) 
    return(filedata) 
} 

leif

6

Denken Sie daran, Ihre Knuth. "Vorzeitige Optimierung ist die Wurzel aller Programmfehler."

Probieren Sie die nebenwirkungsfreie Version. Sehen Sie, ob es Ihren Leistungszielen entspricht. Wenn es so ist, großartig, haben Sie überhaupt kein Problem; Wenn dies nicht der Fall ist, verwenden Sie die Nebenwirkungen und notieren Sie dem nächsten Programmierer, dass Ihre Hand gezwungen wurde.

1

FYI, ist hier eine vollständige Probe Spielzeug-Lösung, die Nebenwirkungen vermeidet:

outerfunc <- function(names) { 
    templist <- list() 
    for (aname in names) { 
    templist[[aname]] <- innerfunc(aname) 
    } 
    templist 
} 

innerfunc <- function(aname) { 
    retval <- NULL 
    if ("one" %in% aname) retval <- c(1) 
    if ("two" %in% aname) retval <- c(1,2) 
    if ("three" %in% aname) retval <- c(1,2,3) 
    retval 
} 

names <- c("one","two","three") 

name_vals <- outerfunc(names) 

for (name in names) assign(name, name_vals[[name]])