2008-09-17 38 views
5

J'ai une fonction dans une boucle à l'intérieur d'une fonction. La fonction interne acquiert et stocke un grand vecteur de données en mémoire (en tant que variable globale ... J'utilise "R" qui est comme "S-Plus"). La boucle boucle une longue liste de données à acquérir. La fonction externe démarre le processus et passe dans la liste des jeux de données à acquérir.Pire péché: effets secondaires ou passage d'objets massifs?

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

I programmé la fonction interne pour stocker chaque jeu de données avant de passer à l'autre, de sorte que tous les travaux de la fonction extérieure se produit comme effets secondaires sur les variables globales ... un grand no-no. Est-ce mieux ou pire que de collecter et de restituer un vecteur géant de vecteurs vecteurs de mémoire? Y a-t-il une troisième approche supérieure?

La réponse changerait-elle si je stockais les vecteurs de données dans une base de données plutôt qu'en mémoire? Idéalement, j'aimerais pouvoir mettre fin à la fonction (ou la faire échouer en raison de dépassements de délai réseau) sans perdre toutes les informations traitées avant la résiliation.

+2

Je recommande éditer ce post pour inclure une brève pseudocode il est plus facile de voir ce que vous essayez de faire –

+0

Oui s'il vous plaît ajouter pseudocode , impossible de savoir ce que tu veux dire. Quand vous dites "traiter ... et stocker le résultat", voulez-vous dire "stocker exactement la même chaîne", ou vecteur (des ints, des mots référents), ou quoi? Est-ce que vous le stockez comme un enregistrement dans un énorme dataframe/array/matrix? Donnez-nous une idée du nombre de lignes, de colonnes, de fichiers, de tailles de blocs et de vecteurs, et de votre mémoire de travail? – smci

Répondre

-1

Il est difficile de dire définitivement sans connaître le langage/compilateur utilisé. Cependant, si vous pouvez simplement passer un pointeur/une référence à l'objet que vous créez, alors la taille de l'objet lui-même n'a rien à voir avec la vitesse des appels de fonction. Manipuler ces données sur la route pourrait être une histoire différente.

+1

La langue qu'il utilise est R: http://r-project.org/ – Allen

10

utiliser des variables dans la fonction externe plutôt que des variables globales. Cela vous permet d'obtenir le meilleur des deux approches: vous ne mutuez pas l'état global et vous ne copiez pas une grande quantité de données. Si vous devez quitter tôt, renvoyez simplement les résultats partiels.

(Voir la section « Champ d'application » dans le manuel R: http://cran.r-project.org/doc/manuals/R-intro.html#Scope)

0

Troisième approche: fonction interne renvoie une référence au grand tableau, qui l'instruction suivante dans la boucle puis déréférence et magasins partout où il est nécessaire (idéalement avec un seul pointeur et pas en ayant à mémoriser l'ensemble du tableau).

Cela supprime à la fois l'effet de bord et le passage de grandes structures de données.

4

Cela ne va pas faire une grande différence pour l'utilisation de la mémoire, donc vous pourriez aussi bien nettoyer le code.

Puisque R a une fonction de copie-sur-modification pour les variables, la modification de l'objet global aura les mêmes implications en termes de mémoire que de transmettre quelque chose dans les valeurs de retour.

Si vous stockez les sorties dans une base de données (ou même dans un fichier), vous ne rencontrerez pas de problèmes d'utilisation de la mémoire et les données seront progressivement disponibles au moment de la création. Que ce soit plus rapide avec la base de données dépend principalement de la quantité de mémoire que vous utilisez: est-ce que la réduction est la récupération de la mémoire va payer pour le coût de l'écriture sur le disque.

Il y a des profileurs de temps et de mémoire dans R, de sorte que vous pouvez voir empiriquement quels sont les impacts.

1

Je ne suis pas sûr de comprendre la question, mais j'ai quelques solutions.

  1. À l'intérieur de la fonction, créez une liste des vecteurs et renvoyez-la.

  2. A l'intérieur de la fonction, créez un environnement et stockez tous les vecteurs qui s'y trouvent. Assurez-vous simplement de renvoyer l'environnement en cas d'erreur.

dans 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

Rappelez-vous votre Knuth. "L'optimisation prématurée est la racine de tout mal de programmation."

Essayez la version sans effets secondaires. Voyez si cela répond à vos objectifs de performance. Si c'est le cas, génial, vous n'avez pas de problème en premier lieu; Si ce n'est pas le cas, utilisez les effets secondaires et notez au programmeur suivant que votre main a été forcée.

1

Pour votre information, voici une solution de jouets de l'échantillon complet qui permet d'éviter les effets secondaires:

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]])