Ausführungszeit der Haskell-Funktion

73

Gibt es eine einfache Methode, um die Zeit der Funktionsausführung in Haskell zu berechnen?

0xAX
quelle
Die Antworten auf meine Frage zum Kriterium können einige hilfreiche Verwendungsbeispiele enthalten . stackoverflow.com/questions/6637968/… .
Gatoatigrado
3
Dies ist auch eine etwas nuancierte Situation, da Funktionen in Haskell nicht vollständig "ausgeführt" werden müssen. Sie müssen nur für den gewünschten Wert ausreichend erweitert werden. Betrachten Sie head [1..], welches das erste Element einer unendlichen Liste nimmt.
Gatoatigrado
@gatoatigrado Deshalb hat das Kriterium die whnfund nfFunktionen.
Alternative

Antworten:

109

Einfachstes Dinge einfach zu tun , :set +sin ghci, und dann können Sie die Ausführungszeit alles , was Sie ausführen, zusammen mit der Speichernutzung sehen.

Rafal
quelle
21
Funktionen laufen in ghci jedoch viel langsamer. In meinem Test etwa 10 mal langsamer.
Ray
3
Ist es möglich, die Genauigkeit der gemessenen Zeit wie in Millisekunden einzustellen?
SiXoS
1
Langsamer, ja, aber dies scheint sehr wertvoll zu sein, um Unterschiede im Zeit- und Raumverbrauch zwischen Algorithmen aufzuzeigen. Zum Beispiel <pre> <code> slow_fib :: Int -> Integer slow_fib 0 = 0 slow_fib 1 = 1 slow_fib n = slow_fib (n-2) + slow_fib (n-1) - vs. memoized_fib :: Int -> Integer memoized_fib = (map fib [0 ..] !!) wobei fib 0 = 0 fib 1 = 1 fib n = memoized_fib (n-2) + memoized_fib (n-1) </ pre> </ code> Wo Sie sehen können Die erste Funktion nimmt nicht nur viel mehr Zeit in Anspruch, sondern auch mehrere Größenordnungen mehr Platz.
Alex Hart
28

Das criterionPaket wurde speziell dafür entwickelt.

Daniel Wagner
quelle
6

Der Benchmark für die Funktionsausführungszeit ist in Criterion.Measurement enthalten

Zum Beispiel, wenn ich die Zeit von erfassen möchte someIOFunction :: IO ()

import Criterion.Measurement
main = secs <$> time_ someIOFunction >>= print
Zane XY
quelle
Dies wird nicht mehr unterstützt - scheint veraltet zu sein.
Chris Stryczynski
3

Kriterium ist die ausgefeilteste Methode, obwohl ich es schwierig fand, sie zu starten, und sie scheint auf Benchmarking-Programme ausgerichtet zu sein. Ich wollte den Ausführungszeitpunkt berechnen und diese Daten in meinem Programm verwenden, und es scheint diesen Bedarf nicht zu decken, zumindest ist dies nicht sofort ersichtlich.

TimeIt ist sehr einfach und macht das, was ich wollte, außer dass es reine Funktionen nicht gut handhabt. Die für eine reine Funktion zurückgegebene Zeit ist die Thunk Allocation Time (AFAIK), und selbst bei Verwendung von seq kann es schwierig sein, das zu bekommen, was Sie wollen.

Was für mich funktioniert, basiert auf TimeIt.

import System.TimeIt

timeItTPure :: (a -> ()) -> a -> IO (Double,a)
timeItTPure p a = timeItT $ p a `seq` return a

In timeItTPure pa ist p die Funktion, die für die Bewertung des Ergebnisses einer reinen Berechnung a verantwortlich ist, so tief wie nötig, um das gute Bewertungszeitpunkt zu erhalten. Vielleicht ist dies eine einfache Musterübereinstimmung, vielleicht zählt es die Länge einer Liste, vielleicht ist es die Folge jedes Elements in der Liste, vielleicht ist es eine Deepseq usw.

Die Verwendung von seq ist schwierig. Beachten Sie, dass die folgende Funktion nicht wie gewünscht ausgeführt wird. Haskell ist eine mysteriöse Sache.

badTimeItTPure a = timeItT . return $ seq (p a) a
Trevor kochen
quelle
0

https://github.com/chrissound/FuckItTimer

start' <- start
timerc start' "begin"
print "hello"
timerc start' "after printing hello"
benchmark
timerc start' "end"
end <- getVals start'
forM_ (timert end) putStrLn

Ausgänge:

"hello"
begin -> after printing hello: 0.000039555s
after printing hello -> end: 1.333936928s

Dies scheint für meinen sehr einfachen Anwendungsfall gut zu funktionieren.

Chris Stryczynski
quelle
Hmmmm .... Versucht zu bearbeiten, um die Hervorhebung richtig zu machen, aber offensichtlich mag es mich nicht. Es tut uns leid.
dfeuer