8
votes

Tableaux de type C à Perl

Je veux créer et manipuler de grandes tableaux de (4 octets) en mémoire en mémoire. Par grand, je veux dire sur l'ordre de centaines de millions. Chaque cellule de la matrice agira comme un compteur pour une position sur un chromosome. Tout ce dont j'ai besoin, c'est que cela s'adapte à la mémoire et d'avoir un accès rapide (O (1)) aux éléments. La chose que je compte n'est pas une caractéristique clairsemée, je ne peux donc pas utiliser un tableau rare.

Je ne peux pas faire cela avec une liste de perl régulière, car Perl (au moins sur ma machine) utilise 64 octets par élément, de sorte que les génomes de la plupart des organismes que je travaille sont trop gros. J'ai essayé de stocker les données sur disque via SQLite et hachage, et bien qu'ils fonctionnent, sont très lents, en particulier sur des lecteurs ordinaires. (Cela fonctionne raisonnablement d'accord lorsque je fonctionne sur un raid à 4 lits 0).

Je pensais utiliser des tableaux PDL, B / C PDL stocke ses tableaux tout comme c, en utilisant seulement 4 octets par élément. Cependant, j'ai constaté que la vitesse de mise à jour lente d'excrétiser par rapport aux listes Perl: xxx

retourne: xxx

Est-ce que quelqu'un Savoir comment augmenter les performances définies PDL () ou savoir un module différent pouvant accomplir cela?


1 commentaires

Avez-vous regardé les modules de Bioinformatics Perl?


7 Réponses :


2
votes

PDL gagne lorsque les opérations peuvent être filetées, apparemment, elle n'est pas optimisée pour un accès aléatoire et une affectation. Peut-être que quelqu'un avec plus de connaissances PDL pourrait aider.


2 commentaires

Ce n'est pas l'accès aléatoire mais le temps de démarrage pour initialiser les structures de données PDL. Selon le calcul impliqué, le PDL nécessite de 100 à 1 000 éléments à traiter avant de percer même en performance avec des opérations de Perl autochtones. Avec son soutien à la boucle implicite, une ligne de code PDL peut remplacer plusieurs boucles de scalaire ou de liste imbriquées dans des perl ordinaires.


Vous seriez le meilleur à savoir, merci pour le commentaire. Certainement, il y a de meilleures réponses postées dans cette question maintenant que la mienne. :-)



8
votes

Je ne peux pas dire quel type de performance vous obtiendrez, mais je recommande d'utiliser la fonction VEC code>, documentée ici , pour diviser une chaîne en champs de bits. J'ai expérimenté et j'ai constaté que mon Perl tolérera une chaîne jusqu'à 500_000_000 code> caractères longtemps. Ce qui correspond à 125 000 000 valeurs 32 bits.

          Rate  pdl  vec perl
pdl   472429/s   -- -76% -85%
vec  1993101/s 322%   -- -37%
perl 3157570/s 568%  58%   --


0 commentaires

2
votes

Emballé :: Array sur CPAN pourrait vous aider.

Emballé :: Array fournit une classe d'entière compensée signée. Les tableaux construits à l'aide d'emballés :: Array ne peuvent contenir que des entiers signés qui correspondent à vos entiers natifs à la plate-forme, mais ne prenez que autant de mémoire que nécessaire pour contenir ces entiers. Ainsi, pour les systèmes 32 bits, plutôt que de prendre environ 20 octets par entrée de réseau, ils ne prennent que 4.


1 commentaires

Oui j'ai regardé ce module, ainsi que Cravate :: Array :: Pack , Cravate :: Array :: Emballé , Cravate :: Vecarray et Cravate :: Array :: Packedc . Malheureusement, le Perl Cravate API est très lent et le plus rapide ( Array :: Array :: Emballé ) reste dix fois plus lent que les matrices natives.



7
votes

La commande PDL que vous voulez est indadd code>. (Merci à Chris Marshall, PDL Pumpking, pour le pointant sur moi ailleurs .)

PDL est conçu pour ce que j'appelle des opérations "vectorisées". Par rapport aux opérations C, les opérations de Perl sont assez lentes. Vous souhaitez donc conserver le nombre d'invocations de méthode PDL au minimum et que chaque invocation ait beaucoup de travail. Par exemple, ce benchmark vous permet de spécifier le nombre de mises à jour à effectuer en une seule go (en tant que paramètre de ligne de commande). Le côté Perl doit boucler, mais le côté PDL ne fonctionne que cinq appels de fonction: p> xxx pré>

Quand je l'exécute avec un argument de 1, je reçois encore pire des performances que Lorsque vous utilisez définir code>, ce que je m'attendais à: p> xxx pré>

C'est beaucoup de terrain à maquillage! Mais tenez là-bas. Si nous faisons 100 itérations par tour, nous obtenons une amélioration: p> xxx pré>

et avec 10 000 mises à jour par tour, PDL surperforms Perl par un facteur de quatre: p>

use PDL;
use Benchmark qw/cmpthese/;

my $updates_per_round = shift || 1;

my $N = 1_000_000;
my @perl = (0 .. $N - 1);
my $pdl = zeroes $N;
my $inline = pack "d*", @perl;
my $max_PDL_per_round = 5_000;

use Inline 'C';

cmpthese(-1,{ 
    perl => sub{
        $perl[int(rand($N))]++ for (1..$updates_per_round);
    },
    pdl => sub{
        my $to_update = long(random($updates_per_round) * $N);
        indadd(1,$to_update,$pdl);
    },
    inline => sub{
        do_inline($inline, $updates_per_round, $N);
    },
});


__END__

__C__

void do_inline(char * packed_data, int N_updates, int N_data) {
    double * actual_data = (double *) packed_data;
    int i;
    for (i = 0; i < N_updates; i++) {
        int index = rand() % N_data;
        actual_data[index]++;
    }
}


0 commentaires

4
votes

pdl :: Set () code> et pdl :: get (get () code> est destiné à une aide d'apprentissage que toute autre chose. Ils constituent le moyen pessimal d'accéder aux variables PDL. Vous seriez bien mieux d'utiliser certaines des routines d'accès en vrac intégrées. Le constructeur PDL accepte lui-même les listes PERL:

$pdl->bswap4;
$dr = $pdl->get_dataref;
vec($$dr,int(rand($N)),32)++;
$pdl->upd_data;
$pdl->bswap4;


0 commentaires

2
votes

depuis que vous utilisiez des entiers, ce qui devrait être ok pour une utilisation avec des chromosomes, essayez ceci xxx

et le put que j'ai eu à partir de c'était ... xxx

qui montre une grande différence de performance de quand j'ai essayé d'abord ce code sans Ajouter dans mes 2 cents, j'ai reçu xxx


0 commentaires

0
votes

ma réponse ci-dessus peut être sans valeur ... Cela pourrait aider.

$PDL::BIGPDL=1;


0 commentaires