J'essaie d'obtenir la longueur moyenne de FASTA Séquences en utilisant Erlang strong>. Un fichier FASTA ressemble à ceci J'ai essayé de répondre à cette question en utilisant le code suivant erlang fort> code: p> compilation / exécution forte>: p> Ce code semble fonctionner correctement pour un petit fichier FASTA, mais il faut des heures pour analyser une plus grande (> 100mo ). Pourquoi ? Je suis un erlang novice, pouvez-vous améliorer ce code? P> p>
5 Réponses :
J'ai aussi apprencez Erlang, merci pour la question amusante.
Je comprends travailler avec Erlang Strings lorsque des listes de caractères peuvent être très lentes; Si vous pouvez Travaillez avec des binaires à la place, vous devriez voir des gains de performance. Je ne sais pas comment vous utiliseriez des chaînes de longueur arbitraire avec des fichiers binaires, mais si vous pouvez trier le coup, cela devrait aider. P>
Aussi, si cela ne vous dérange pas de travailler avec un fichier directement plutôt que de Je m'attendais à ce que le Utilisation de Utilisation de Voici où je me tiens maintenant; Si vous pouvez comprendre comment utiliser des fichiers binaires au lieu de listes, cela pourrait voir encore plus d'amélioration: p> Standard_IO Code>, peut-être que vous pourriez peut-être accélérer les choses en utilisant
Fichier: Ouvrir (..., [RAW, READ_AHEAD]) CODE>.
RAW CODE> signifie que le fichier doit figurer sur le système de fichiers du nœud local et
read_ahead code> Spécifie que Erlang doit effectuer un fichier io avec un tampon. (Pensez à utiliser les installations de Stdio de C avec et sans tampon.) P>
read_ahad code> Pour faire la plus grande différence, mais tout avec Erlang inclut la phrase "référence avant de deviner" «. Code> 1m31s code> sur l'ensemble de données UNIPROT_SPROT.FASTA. (Moyenne 359.04679841439776.) P>
Fichier: Ouvrir (.., [Lire, Read_Ahead]) Code> et
Fichier: read_line (s) code>, je reçois
0m34s code>. P>
Fichier: Ouvrir (.., [Lire, read_ahead, brut]) code> et
Fichier: read_line (s) < / Code>, je reçois
0m9s code>. Oui, neuf secondes. P>
Merci Arnold, je te teste actuellement de solution. erl (version = r13b01) a soulevé une erreur: "{" init terminant dans do_boot ", {UNDEF, [{File, read_line, [{File_Descriptor, prim_file, {# Port <0.286>, 7}}]}, {golf, scanlines, 3}, {golf, test, 0}, {init, start_it, 1}, {init, st art_em, 1}]}} ". Une idée ?
Ok, j'ai dit que ma version ne prend pas en charge R13B01, je vais tester cela demain sur un autre ordinateur.
On dirait que vos problèmes de performances ont été résolus en ouvrant le fichier en mode brut, mais voici quelques pensées supplémentaires si vous avez besoin d'optimiser ce code plus loin. P>
Apprendre et utiliser FPROF. P>
Vous utilisez Je suis méfiant des conseils qui indiquent que les fichiers binaires sont meilleurs que des listes, mais étant donné à quel point vous traitez probablement le cas ici. Les premières étapes consistent à ouvrir le fichier en mode binaire et à utiliser Cela n'affectera pas les performances (de manière significative), mais la multiplication par 1,0 dans String: Strip / 1 code> principalement pour supprimer la nouvelle ligne de fuite. Comme les valeurs d'Erlang sont immuables, vous devez effectuer une copie complète de la liste (avec toutes les allocations de mémoire associées) pour supprimer le dernier caractère. Si vous connaissez le fichier est bien formé, il suffit de soustraire un de votre compte, sinon j'essayerais d'écrire une fonction de longueur, le nombre de caractères pertinents et ignore les pertinents. P>
erlang: taille / 1 code> pour trouver la longueur. P>
total / (1,0 * séquences) code> n'est nécessaire que dans des langues avec une division brisée. La division Erlang fonctionne correctement. P>
L'appel String: LEN (String: Strip (L)) Code> traverse la liste au moins deux fois (je ne suis pas au courant de la chaîne: mise en œuvre de la bande). Au lieu de cela, vous pouvez écrire une fonction simple pour compter la longueur de la ligne avec les espaces:
stripped_len(L) ->
stripped_len(L, 0).
stripped_len([$ |L], Len) ->
stripped_len(L, Len);
stripped_len([_C|L], Len) ->
stripped_len(L, Len + 1);
stripped_len([], Len) ->
Len.
Si vous avez besoin de vraiment rapide io, vous devez faire un peu plus de tenter que d'habitude.
$ erl -smp disable -noinput -mode minimal -boot start_clean -s erl_compile compile_cmdline @cwd /home/hynek/Download @option native @option '{hipe, [o3]}' @files golf.erl ./golf.erl:5: Warning: variable 'Rest' is unused $ time erl -smp disable -noshell -mode minimal -s golf test 359.04679841439776 real 0m17.569s user 0m16.749s sys 0m0.664s
Excellent! Merci pour l'exemple; Pouvez-vous souligner pourquoi nos versions obtiennent des réponses différentes? Merci!
@Sarnold: Je n'ai pas assez de temps pour regarder votre version où est le problème. Je suppose que c'est une trailing "\ n" qui peut être dépouillé par string: bande / 1 code> mais je ne suis pas sûr. J'ai vérifié par ce code
perl -nle '/ ^> /? $ C ++: ($ B + = longueur ((/ (\ s *) /) [0]))} {imprimé $ B / $ C' < / Code> Pour être sûr que la version de la mine n'a pas le même bug que tous les autres sur biostar.stackexchange.com/questions / 1759 Mais tout semble bien et 352.6697028442464 devrait avoir une bonne réponse.
@Sarnold: Une vérification très simple me dit que "\ n" est-ce. Lorsque vous soustrayez l'une de chaque longueur de ligne, vous obtenez une bonne réponse, donc cela signifie fichier: read_line / 1 code> renvoie la ligne avec la nouvelle ligne Char et
String: Strip / 1 code> ne supprime pas ce.
Merci! Je ne pouvais pas comprendre où nos versions produisaient des calculs différents ...
Avez-vous essayé Elixir (Elixir-lang.org) qui fonctionne sur Erlang et a une syntaxe similaire à Ruby. Elixir résout des problèmes de chaîne de la manière suivante: p>
Les chaînes d'Elixir sont des fichiers binaires UTF8, avec toute la vitesse brute et la mémoire économies qui apporte. Elixir a un module de chaîne avec Unicode fonctionnalité intégrée et est un excellent exemple de code d'écriture qui écrit le code. String.unicode lit divers décharges de base de données Unicode tels que comme unicodedata.txt pour générer de manière dynamique des fonctions Unicode pour la Module de chaîne construit directement à partir de ces données! ( http://devintorr.es/blog/2013/01 / 22 / The-Excitement-of-Elixir / ) P> blockQuote>
Je me demande simplement si Elixir serait plus rapide? P>
Vous ne devriez pas deviner mais mesurer.
Voir aussi le 'Challenge' original: biostar.stackexchange.com/questions/1759
WOW, excellente collection d'échantillons de code non triviaux à partir d'un large éventail de langues. Merci!