2013-07-24 16 views
9

il problemaprestazioni Haskell quando si usano le classi e le istanze

voglio simulare in Haskell un multivalore funzioni output. Il codice Haskell è generato (non scritto a mano) - si tratta di informazioni importanti, vedere sotto:

Questo può essere, naturalmente, facilmente fatto restituendo una tupla dalla funzione, come

f x y = (x+y, x-y) 

Ma quando si utilizza tale funzione devo sapere che tipo di tupla restituisce:

... 
(out_f_1, out_f_2)   = f a b 
(out_g_1, out_g_2, out_g_3) = g out_f_1 
... 

E così via ... Ma durante la generazione del codice, non so qual è il tipo di output di f consente di dire, così adesso ho' m utilizzando il pacchetto Data.List.Select e simulare quanto sopra con:

import Data.List.Select 
... 
out_f = f a b 
out_g = g (sel1 outf) 
... 

Il problema è la prestazione - sul mio programma di test, la versione, che usa Data.List.Select è due volte più lento rispetto alla versione scritta a mano.

Questa è la situazione molto evidente, perché Data.List.Select è scritto utilizzando classes e instances, in modo che utilizza una sorta di dizionario runtime (se non sbaglio). (http://hackage.haskell.org/packages/archive/tuple/0.2.0.1/doc/html/src/Data-Tuple-Select.html#sel1)

La questione

voglio chiedervi se è possibile compilare in qualche modo la versione (che utilizza Data.List.Select) di essere veloce come quello realizzato manualmente?

Penso che ci dovrebbe essere un passaggio al compilatore, che gli dirà di "istanziare" le classi e le interfacce per ogni utilizzo (qualcosa come i modelli di C++).

benchmark

Test1.hs:

import qualified Data.Vector as V 
import System.Environment 
b :: Int -> Int 
b x = x + 5 
c x = b x + 1 
d x = b x - 1 
a x = c x + d x 
main = do 
    putStrLn "Starting..." 
    args <- getArgs 
    let iternum = read (head args) :: Int in do 
     putStrLn $ show $ V.foldl' (+) 0 $ V.map (\i -> a (iternum-i)) 
     $ V.enumFromTo 1 iternum 
     putStrLn "Done." 

compilare con ghc -O3 Test1.hs

Test2.hs:

import qualified Data.Vector as V 
import Data.Tuple.Select 
import Data.Tuple.OneTuple 

import System.Environment 
b x = OneTuple $ x + 5 
c x = OneTuple $ (sel1 $ b x) + 1 
d x = OneTuple $ (sel1 $ b x) - 1 
a x = OneTuple $ (sel1 $ c x) + (sel1 $ d x) 
main = do 
    putStrLn "Starting..." 
    args <- getArgs 
    let iternum = read (head args) :: Int in do 
     putStrLn $ show $ V.foldl' (+) 0 $ V.map (\i -> sel1 $ a (iternum-i)) 
     $ V.enumFromTo 1 iternum 
     putStrLn "Done." 

compilare con ghc -O3 Test2.hs

Risultati

time ./Test1 10000000 = 5.54 s 
time ./Test2 10000000 = 10.06 s 
+0

I due benchmark hanno lo stesso per me. In entrambi i casi, producono loop ricorsivi tail operanti su interi non archiviati. Una possibilità per la differenza percepita nelle prestazioni è che il secondo benchmark è più influenzato dal puntatore indiretto aggiuntivo dovuto al wrapping di tutto in 'OneTuple', dal momento che GHC potrebbe facilmente elidere i dizionari typeclass in questo caso. – sabauma

+0

@sabauma - ok, ce l'ho! I miei test non sono stati compilati usando il flag '-O3' (perché stavo compilando senza' -force-recompile') così GHC non ha fatto tali ottimizzazioni. Potresti dirmi perché dovremmo usare in qualsiasi momento 'specialize pragma' se il compilatore è in grado di ottimizzare tali espressioni come questa? –

+3

questo è un esempio abbastanza facile da ottimizzare per il compilatore. In questo caso, GHC può elidere le ricerche di typeclass in quanto è in grado di allineare le chiamate polimorfiche e determinare quale istanza di classe tipo utilizzare in fase di compilazione. Non è possibile (o non si vuole) eseguire sempre una funzione di grandi dimensioni, nel qual caso è ancora vantaggioso che GHC produca una versione specializzata della funzione. – sabauma

risposta

0

Ok, i risultati che ho postato non sono precisi - come @sabauma ha detto - i due i codici vengono eseguiti nello stesso momento Se li si compila con le ottimizzazioni abilitate.

La risposta di @ tohava è molto buona se si desidera esplicitamente mostrare quali funzioni si specializzano (vedere il commento di @sabauma sopra).

Problemi correlati