2010-07-21 7 views
6

मैं की औसत लंबाई Erlang का उपयोग करने की कोशिश कर रहा हूं।"फास्ट फ़ाइल में अनुक्रमों की औसत लंबाई": क्या आप इस एर्लांग कोड को बेहतर बना सकते हैं?

-module(golf). 
-export([test/0]). 

line([],{Sequences,Total}) -> {Sequences,Total}; 
line(">" ++ Rest,{Sequences,Total}) -> {Sequences+1,Total}; 
line(L,{Sequences,Total}) -> {Sequences,Total+string:len(string:strip(L))}. 

scanLines(S,Sequences,Total)-> 
     case io:get_line(S,'') of 
      eof -> {Sequences,Total}; 
      {error,_} ->{Sequences,Total}; 
      Line -> {S2,T2}=line(Line,{Sequences,Total}), scanLines(S,S2,T2) 
     end . 

test()-> 
    {Sequences,Total}=scanLines(standard_io,0,0), 
    io:format("~p\n",[Total/(1.0*Sequences)]), 
    halt(). 

संकलन/निष्पादन:

erlc golf.erl 
erl -noshell -s golf test < sequence.fasta 
563.16 

इस कोड को लगता है एक fasta फ़ाइल इस

>title1 
ATGACTAGCTAGCAGCGATCGACCGTCGTACGC 
ATCGATCGCATCGATGCTACGATCGATCATATA 
ATGACTAGCTAGCAGCGATCGACCGTCGTACGC 
ATCGATCGCATCGATGCTACGATCTCGTACGC 
>title2 
ATCGATCGCATCGATGCTACGATCTCGTACGC 
ATGACTAGCTAGCAGCGATCGACCGTCGTACGC 
ATCGATCGCATCGATGCTACGATCGATCATATA 
ATGACTAGCTAGCAGCGATCGACCGTCGTACGC 
>title3 
ATCGATCGCATCGAT(...) 

जैसे मैं निम्नलिखित Erlang कोड का उपयोग कर इस सवाल answser करने की कोशिश की लग रहा है एक छोटी फास्ट फ़ाइल के लिए ठीक काम करने के लिए, लेकिन एक बड़े (> 100 एमओ) पार्स करने में घंटों लगते हैं। क्यूं कर ? मैं एक एरलांग नौसिखिया हूँ, क्या आप इस कोड को बेहतर बना सकते हैं?

+4

मूल 'चुनौती' भी देखें: http://biostar.stackexchange.com/questions/1759 – Pierre

+1

वाह, भाषाओं की विस्तृत श्रृंखला से गैर-तुच्छ कोड नमूने का उत्कृष्ट संग्रह। धन्यवाद! – sarnold

उत्तर

5

यदि आपको वास्तव में तेज़ आईओ की आवश्यकता है तो आपको सामान्य से थोड़ा अधिक ट्रिकरी करना होगा।

-module(g). 
-export([s/0]). 
s()-> 
    P = open_port({fd, 0, 1}, [in, binary, {line, 256}]), 
    r(P, 0, 0), 
    halt(). 
r(P, C, L) -> 
    receive 
    {P, {data, {eol, <<$>:8, _/binary>>}}} -> 
     r(P, C+1, L); 
    {P, {data, {eol, Line}}} -> 
     r(P, C, L + size(Line)); 
    {'EXIT', P, normal} -> 
     io:format("~p~n",[L/C]) 
    end. 

यह रूप में मैं जानता हूँ कि लेकिन ध्यान दें -noshell -noinput सबसे तेजी से आईओ है। संकलित सिर्फ erlc +native +"{hipe, [o3]}" g.erl पसंद है, लेकिन साथ -smp disable

erl -smp disable -noinput -mode minimal -boot start_clean -s erl_compile compile_cmdline @cwd /home/hynek/Download @option native @option '{hipe, [o3]}' @files g.erl 

और चलाएँ:

time erl -smp disable -noshell -mode minimal -boot start_clean -noinput -s g s < uniprot_sprot.fasta 
352.6697028442464 

real 0m3.241s 
user 0m3.060s 
sys  0m0.124s 
-smp enable साथ

लेकिन देशी यह लेता है:

$ erlc +native +"{hipe, [o3]}" g.erl 
$ time erl -noshell -mode minimal -boot start_clean -noinput -s g s<uniprot_sprot.fasta 
352.6697028442464 

real 0m5.103s 
user 0m4.944s 
sys  0m0.112s 

बाइट कोड लेकिन (लगभग देशी के साथ बराबर में -smp disable साथ क्योंकि अधिकांश काम बंदरगाह में किया जाता है!):

$ erlc g.erl 
$ time erl -smp disable -noshell -mode minimal -boot start_clean -noinput -s g s<uniprot_sprot.fasta 
352.6697028442464 

real 0m3.565s 
user 0m3.436s 
sys  0m0.104s 

बस SMP साथ पूर्णता बाइट कोड के लिए:

$ time erl -noshell -mode minimal -boot start_clean -noinput -s g s<uniprot_sprot.fasta 
352.6697028442464 

real 0m5.433s 
user 0m5.236s 
sys  0m0.128s 

तुलना sarnoldversion के लिए मुझे गलत जवाब देता है और एक ही HW पर अधिक लेता है:

$ 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 

संपादित: मैं ध्यान दिया है uniprot_sprot.fasta की विशेषताओं पर और मैं थोड़ा आश्चर्यचकित हूं। यह 3824397 पंक्तियां और 232 एमबी है। इसका मतलब है कि -smp disabled संस्करण प्रति सेकंड 1.18 मिलियन टेक्स्ट लाइनों को नियंत्रित कर सकता है (लाइन उन्मुख आईओ में 71 एमबी/एस)।

+0

बहुत रोचक, धन्यवाद। – Pierre

+0

उत्कृष्ट! उदाहरण के लिए धन्यवाद; क्या आप बता सकते हैं कि हमारे संस्करणों को अलग-अलग उत्तर क्यों मिल रहे हैं? धन्यवाद! – sarnold

+0

@ कर्नाल्ड: मेरे पास आपके संस्करण को देखने के लिए पर्याप्त समय नहीं है जहां समस्या है। मुझे लगता है कि यह पीछे है "\ n" जो स्ट्रिंग: स्ट्रिप/1' द्वारा नहीं छोड़ा जा सकता है लेकिन मुझे यकीन नहीं है। मैंने इस कोड 'perl -nle'/^> /? $ C++: ($ b + = लंबाई ((/ (\ S *) /) [0]))} {{$ b/$ c'' प्रिंट होने के लिए) सुनिश्चित करें कि मेरा संस्करण http://biostar.stackexchange.com/questions/1759 पर अन्य सभी के समान नहीं है लेकिन सभी ठीक लगता है और 352.6697028442464 सही उत्तर होना चाहिए। –

3

मैं भी मर्ल प्रश्न सीख रहा हूं, मजेदार सवाल के लिए धन्यवाद।

मैं एरलांग तारों के साथ काम करना समझता हूं क्योंकि वर्णों की सूचियां बहुत धीमी हो सकती हैं; यदि आप work with binaries कर सकते हैं तो आपको कुछ प्रदर्शन लाभ देखना चाहिए। मुझे नहीं पता कि आप द्विआधारी के साथ मनमानी-लंबाई तारों का उपयोग कैसे करेंगे, लेकिन यदि आप इसे हल कर सकते हैं, तो इसे मदद करनी चाहिए।

इसके अलावा, अगर आपको standard_io की बजाय सीधे फ़ाइल के साथ काम करने में कोई फर्क नहीं पड़ता है, तो शायद आप file:open(..., [raw, read_ahead]) का उपयोग कर चीजों को गति दे सकते हैं। raw का अर्थ है कि फ़ाइल स्थानीय नोड की फाइल सिस्टम पर होनी चाहिए, और read_ahead निर्दिष्ट करता है कि एरलांग को फ़ाइल IO को बफर के साथ निष्पादित करना चाहिए। (बफरिंग के साथ और बिना सी के स्टडीओ सुविधाओं का उपयोग करने के बारे में सोचें।)

मैं सबसे अधिक अंतर बनाने के लिए read_ahead की अपेक्षा करता हूं, लेकिन एरलांग के साथ सब कुछ वाक्यांश "बेंचमार्क अनुमान लगाने से पहले" वाक्यांश शामिल है।

संपादित

file:open("uniprot_sprot.fasta", [read, read_ahead]) का उपयोग 1m31s पूर्ण uniprot_sprot.fasta डेटासेट पर हो जाता है। (औसत 35 9.04679841439776।)

file:open(.., [read, read_ahead]) और file:read_line(S) का उपयोग करके, मुझे 0m34s मिलता है।

file:open(.., [read, read_ahead, raw]) और file:read_line(S) का उपयोग करके, मुझे 0m9s मिलता है। हाँ, नौ सेकंड।

यहां मैं कहां खड़ा हूं; यदि आप पता लगा सकते हैं कि कैसे सूचियों के बजाय बाइनरी उपयोग करने के लिए, यह अभी भी अधिक सुधार देख सकते हैं:

-module(golf). 
-export([test/0]). 

line([],{Sequences,Total}) -> {Sequences,Total}; 
line(">" ++ Rest,{Sequences,Total}) -> {Sequences+1,Total}; 
line(L,{Sequences,Total}) -> {Sequences,Total+string:len(string:strip(L))}. 

scanLines(S,Sequences,Total)-> 
     case file:read_line(S) of 
      eof -> {Sequences,Total}; 
      {error,_} ->{Sequences,Total}; 
      {ok, Line} -> {S2,T2}=line(Line,{Sequences,Total}), scanLines(S,S2,T2) 
     end . 

test()-> 
    F = file:open("/home/sarnold/tmp/uniprot_sprot.fasta", [read, read_ahead, raw]), 
    case F of 
    { ok, File } -> 
     {Sequences,Total}=scanLines(File,0,0), 
     io:format("~p\n",[Total/(1.0*Sequences)]); 
    { error, Reason } -> 
      io:format("~s", Reason) 
    end, 
    halt(). 
+0

धन्यवाद अर्नोल्ड, मैं वर्तमान में आपको समाधान का परीक्षण कर रहा हूं। erl (संस्करण = R13B01) ने एक त्रुटि उठाई: "{" in_boot में समाप्ति init ", {undef, [{file, read_line, [{file_descriptor, prim_file, {# पोर्ट <0.286>, 7}}]}, {गोल्फ, स्कैनलाइन, 3}, {गोल्फ, टेस्ट, 0}, {init, start_it, 1}, {init, start_em, 1}]}} "। कोई उपाय ? – Pierre

+0

ठीक है, मैंने कहा है कि मेरा संस्करण R13B01 का समर्थन नहीं करता है, मैं कल इस दूसरे कंप्यूटर पर परीक्षण करूंगा। – Pierre

2

ऐसा लगता है कि अपने बड़े प्रदर्शन की समस्याओं जैसे कच्चे मोड में फ़ाइल खोलने कर सुलझाई जा सकती है, लेकिन यहां कुछ और विचार है अगर आपको उस कोड को और अनुकूलित करने की आवश्यकता है।

जानें और fprof का उपयोग करें।

आप मुख्य रूप से पिछली नई लाइन को हटाने के लिए string:strip/1 का उपयोग कर रहे हैं। चूंकि erlang मान अपरिवर्तनीय हैं, आपको अंतिम चरित्र को हटाने के लिए सूची की पूरी प्रतिलिपि (सभी संबंधित स्मृति आवंटन के साथ) बनाना है। यदि आपको पता है कि फ़ाइल अच्छी तरह से बनाई गई है, तो बस अपनी गिनती से एक घटाएं, अन्यथा मैं एक लम्बा कार्य लिखने की कोशिश करता हूं जो प्रासंगिक वर्णों की संख्या को गिना जाता है और अप्रासंगिक लोगों को अनदेखा करता है।

मैं सलाह से सावधान हूं कि कहानियां सूचियों से बेहतर हैं, लेकिन यह देखते हुए कि यह संभवतः यहां कितना मामला है। पहला कदम फ़ाइल को बाइनरी मोड में खोलना और लंबाई खोजने के लिए erlang:size/1 का उपयोग करना है।

यह प्रदर्शन (महत्वपूर्ण) को प्रभावित नहीं करेगा, लेकिन Total/(1.0*Sequences) में 1.0 द्वारा गुणा को तोड़ने वाले विभाजन वाले भाषाओं में आवश्यक है। Erlang विभाजन सही ढंग से काम करता है।

1

कॉल string:len(string:strip(L)) कम से कम दो बार सूची में ट्रैवर करता है (मुझे स्ट्रिंग से अनजान है: स्ट्रिप कार्यान्वयन)। इसके बजाय आप लाइन की लंबाई डब्ल्यू/0 रिक्त स्थान की गणना करने के लिए एक सरल समारोह लिख सकते हैं:

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. 

एक ही विधि के साथ-साथ बाइनरी के लिए लागू किया जा सकता है।

0

क्या आपने एलीक्सिर (elixir-lang.org) को आजमाया है जो एरलांग के शीर्ष पर चलता है और रूबी के समान वाक्यविन्यास है। अमृत ​​निम्नलिखित तरीके से स्ट्रिंग समस्याओं को हल करती है:

अमृत तार UTF8 बाइनरी, सभी कच्चे गति और स्मृति बचत कि लाता है के साथ कर रहे हैं। एलिक्सीर में यूनिकोड कार्यक्षमता अंतर्निहित कार्यक्षमता वाला एक स्ट्रिंग मॉड्यूल है और कोड लिखने का एक अच्छा उदाहरण है। String.Unicode के रूप में विभिन्न यूनिकोड डेटाबेस डंप को स्ट्रिंग मॉड्यूल के लिए यूनिकोड फ़ंक्शंस को गतिशील रूप से उत्पन्न करने के लिए उस डेटा से सीधे बनाए गए स्ट्रिंग मॉड्यूल के लिए यूनिकोडडेटा.txt के रूप में पढ़ता है!(http://devintorr.es/blog/2013/01/22/the-excitement-of-elixir/)

बस आश्चर्य है कि क्या एलिक्सीर तेज होगा?

+0

आपको अनुमान नहीं लगाया जाना चाहिए लेकिन मापना चाहिए। –

संबंधित मुद्दे