2010-06-29 4 views
4

J'ai ce code:Est-ce que F # fait une mémoisation automatique?

for i in 1 .. 10 do 
    let (tree, interval) = time (fun() -> insert [12.; 6. + 1.0] exampletree 128.) 
    printfn "insertion time: %A" interval.TotalMilliseconds 
    () 

avec la fonction de temps définie comme

let time f = 
    let start = DateTime.Now 
    let res = f() 
    let finish = DateTime.Now 
    (res, finish - start) 

l'insert de la fonction n'est pas pertinente, autre que le fait qu'il n'utilise pas la mutation et retourne ainsi la même valeur à chaque fois.

-je obtenir les résultats:

insertion time: 218.75 
insertion time: 0.0 
insertion time: 0.0 
insertion time: 0.0 
insertion time: 0.0 
insertion time: 0.0 
insertion time: 0.0 
insertion time: 0.0 
insertion time: 0.0 
insertion time: 0.0 

La question est pourquoi le code calcule le résultat qu'une seule fois (à partir du moment de l'insertion, le résultat est toujours correct et égal)? Aussi, comment forcer le programme à faire des calculs plusieurs fois (j'en ai besoin pour le profilage)?

Edit: Jared a fourni la bonne réponse. Maintenant que je sais ce qu'il faut chercher, je peux obtenir le code du chronomètre de a timeit function for F#

J'ai eu les résultats suivants:

insertion time: 243.4247 
insertion time: 0.0768 
insertion time: 0.0636 
insertion time: 0.0617 
insertion time: 0.065 
insertion time: 0.0564 
insertion time: 0.062 
insertion time: 0.069 
insertion time: 0.0656 
insertion time: 0.0553 

Répondre

15

F # ne fait pas memoization automatique de vos fonctions. Dans ce cas, la mémorisation serait incorrecte. Même si vous ne modifiez pas directement les éléments, vous accédez à une valeur modifiable (DateTime.Now) depuis votre fonction. Memoizing ou une fonction accédant à ce serait une erreur, car il peut changer d'appel à l'appel.

Ce que vous voyez ici est un effet du .Net JIT. La première fois que cette fonction est exécutée, la fonction f() est JIT'd et produit un délai notable. Les autres fois il est déjà JIT'd et exécute un temps qui est inférieure à la granularité des DateTime

Une façon de prouver est d'utiliser une classe de mesure plus granulaire comme StopWatch. Cela montrera la fonction s'exécute plusieurs fois.

+1

+1. Juste pour être clair: le premier appel est plus lent pour le code natif (par exemple écrit en C), aussi, car il doit être chargé en mémoire, à partir de là dans le cache; prédiction de branche pourrait faire un pire travail la première fois, etc – Niki

+3

+1 pour 'System.Diagnostics.Stopwatch', c'est votre bon ami pour le profilage – Brian

+0

Merci. Cela fonctionne, et j'ai édité/fermé la question en conséquence. –

4

La première synchronisation est probablement due à la compilation JIT. Le code que vous synchronisez fonctionne probablement en moins de temps que DateTime est capable de mesurer. Editer: Battu par 18 secs ... Je suis juste content d'avoir eu la bonne idée :)