11 votes

Haskell ou F# E/S binaire à haut débit

À quel point la performance des bibliothèques d'E/S binaires est-elle bonne dans ces deux langages? Je pense à réécrire un code C++ laid (mais très rapide) qui traite des fichiers binaires d'environ 5-10 Go en utilisant les fonctions standard fread et fwrite. Quel facteur de ralentissement devrais-je m'attendre à voir pour une implémentation optimisée en F# et Haskell?

ÉDITER: voici l'implémentation en C du comptage des zéros (tampon alloué sur le tas).

#include 
#include 

#define SIZE 32*1024
int main(int argc, char* argv[])
{
    FILE *fp;
    char *buf;
    long i = 0, s = 0, l = 0;
    fp = fopen(argv[1], "rb");
    if (!fp) {
        printf("Échec de l'ouverture de %s\n", argv[1]);
        return -1;
    }
    buf = (char *) malloc(SIZE);
    while (!feof(fp)) {
        l = fread(buf, 1, SIZE, fp);
        for (i = 0; i < l; ++i) {
            if (buf[i] == 0) {
                ++s;
            }
        }
    }
    printf("%d\n", s);
    fclose(fp);
    free(buf);
    return 0;
}

Les résultats:

$ gcc -O3 -o ioc io.c
$ ghc --make -O3 -o iohs io.hs
Lien de iohs ...
$ time ./ioc 2.bin
462741044

réel    0m16.171s
utilisateur    0m11.755s
système    0m4.413s
$ time ./iohs 2.bin
4757708340

réel    0m16.879s
utilisateur    0m14.093s
système    0m2.783s
$ ls -lh 2.bin
-rw-r--r-- 1  14G Jan  4 10:05 2.bin

9voto

Don Stewart Points 94361

Haskell en utilisant lazy IO basé sur ByteString, avec un parseur "binaire" devrait être autour des mêmes performances que du code C effectuant le même travail, sur les mêmes types de données.

Les principaux packages à connaître :

8voto

Daniel Pratt Points 8151

Étant donné que ce post implique:

  • Haskell
  • optimisations de code
  • performances de référence

...il est sûr de dire que je suis complètement dépassé. Néanmoins, j'apprends toujours quelque chose quand je me retrouve dépassé, donc c'est parti.

J'ai exploré les modules Haskell Data.ByteString.Lazy.* via Hoogle et trouvé la fonction length pour mesurer la longueur d'un lazy ByteString. Elle est implémentée ainsi:

length :: ByteString -> Int64
length cs = foldlChunks (\n c -> n + fromIntegral (S.length c)) 0 cs

Mmm. Jon a dit que "...Faire un pliage sur des morceaux de fichier en F# est une partie importante de pourquoi c'est rapide..." (mon emphasis). Et cette fonction length semble être implementée de la même manière, avec un pliage par morceaux. Il semble donc que cette fonction est bien plus susceptible d'être comparée de manière 'apples to apples' au code F# de Jon.

Cela fait-il une différence en pratique? J'ai comparé l'exemple de Jon avec le suivant:

import System
import Data.List
import Data.ByteString.Lazy as B

main =
    getArgs
    >>= B.readFile . Data.List.head
    >>= print . B.length

L'exemple Haskell de Jon sur ma machine pour un fichier de 1.2 Go: 10.5s

La version 'par morceaux': 1.1s

La version 'par morceaux' du code Haskell est presque dix fois plus rapide. Ce qui suggère qu'elle est probablement plusieurs fois plus rapide que le code F# optimisé de Jon.

MODIFICATION

Alors que je ne suis pas nécessairement en complet accord avec les critiques de Jon sur mon exemple, je voudrais le rendre le plus irréprochable possible. Pour cela, j'ai profilé le code suivant:

import System
import Data.List
import Data.ByteString.Lazy as B

main =
    getArgs
    >>= B.readFile . Data.List.head
    >>= print . B.count 0

Ce code charge le contenu du fichier cible dans un ByteString puis 'compte' chaque occurrence d'un octet de valeur 0. À moins que je ne me trompe, ce programme doit charger et évaluer chaque octet du fichier cible.

Le programme ci-dessus s'exécute de manière constante environ 4 fois plus rapidement que le programme Haskell le plus rapide soumis par Jon, copié ici pour référence (au cas où il serait mis à jour):

import System
import Data.Int
import Data.List
import Data.ByteString.Lazy as B

main =
    getArgs
    >>= B.readFile . Data.List.head
    >>= print . B.foldl (\n c -> n + 1) (0 :: Data.Int.Int64)

2voto

Jon Harrop Points 26951

J'ai parlé de cela ici.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X