Hızlı yanıtım olurdu, awk
ancak çok sayıda satır işliyorsanız - ve milyonlar hakkında konuşuyorsanız - muhtemelen "gerçek" bir programlama diline geçmenin gerçek bir yararı göreceksiniz.
Bunu göz önünde bulundurarak (ve awk
zaten bir cevap olarak alınıyor) farklı dillerde birkaç uygulama yazdım ve bunları bir PCI-E SSD'deki aynı 10.000 satırlı veri kümesinde karşılaştırdım.
me* (C) 0m1.734s
me (C++) 0m1.991s
me (Python/Pypy) 0m2.390s
me (perl) 0m3.024s
Thor+Glenn (sed|sh) 0m3.353s
me (python) 0m3.359s
jasonwryan+Thor (awk) 0m3.779s
rush (while read) 0m6.011s
Thor (sed) 1m30.947s
me (parallel) 4m9.429s
Bir bakışta C en iyi görünüyor ancak bu kadar hızlı koşmak bir domuzdu. Milyarlarca satırdan bahsetmediğiniz sürece Pypy ve C ++ 'ın yazılması ve yeterince iyi performans göstermesi çok daha kolaydır . Bu durumda, tüm bunları RAM'de veya SSD'de yapmak için yapılan bir yükseltme, kod geliştirmeden daha iyi bir yatırım olabilir.
Açıkçası bunlardan geçerken harcadığım zaman muhtemelen en yavaş seçenekte birkaç yüz milyon kayıt işleyebilirdiniz . Sadece awk
Bash döngüleri yazabilir veya yazabiliyorsanız , bunu yapın ve hayata devam edin. Bugün çok fazla boş zamanım vardı.
Ayrıca bazı çok iş parçacıklı seçenekleri (C ++ ve Python ve GNU ile melezler parallel
) test ettim ama iş parçacığı bu tür basit bir işlem (dize bölme, yazma) için herhangi bir fayda tamamen ağır basar.
Perl
awk
( gawk
burada) dürüst olmak gerekirse, bu tür verileri test etmek için ilk çağrı portum olurdu, ancak Perl'de oldukça benzer şeyler yapabilirsiniz. Benzer sözdizimi ancak biraz daha iyi yazma tutamacına sahip.
perl -ane 'open(my $fh, ">", $F[0].".seq"); print $fh $F[1]; close $fh;' infile
piton
Ben gibi Python. Bu benim günlük iş dilim ve sadece güzel, sağlam ve inanılmaz derecede okunabilir bir dil. Yeni başlayanlar bile burada neler olduğunu tahmin edebilir.
with open("infile", "r") as f:
for line in f:
id, chunk = line.split()
with open(id + ".seq", "w") as fw:
fw.write(chunk)
Dağıtımınızın python
ikilisinin Python'un tek uygulaması olmadığını hatırlamanız gerekir . Aynı testi Pypy aracılığıyla yürüttüğümde, daha fazla mantık optimizasyonu olmadan C'den daha hızlıydı . Python'u "yavaş dil" olarak yazmadan önce bunu aklınızdan çıkarmayın.
C
İşlemcimi gerçekten ne elde edebileceğimizi görmek için bu örneğe başladım ama açıkçası C, uzun süre dokunmadıysanız kodlamak için bir kabus. Bunu genişletmek çok basit olsa da, 100 karakterlik çizgilerle sınırlı olmanın ek bir dezavantajı var, sadece ihtiyacım yoktu.
Orijinal versiyonum C ++ ve pypy'den daha yavaştı ama bloglamadan sonra Julian Klode'den biraz yardım aldım . Bu sürüm, tweaked IO tamponları nedeniyle artık en hızlı. Ayrıca her şeyden çok daha uzun ve daha ilgili.
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#define BUFLEN (8 * 1024)
int main(void) {
FILE *fp;
FILE *fpout;
char line[100];
char *id;
char *token;
char *buf = malloc(BUFLEN);
fp = fopen("infile", "r");
setvbuf ( fp , buf , _IOLBF, BUFLEN );
while (fgets(line, 100, fp) != NULL) {
id = strtok(line, "\t");
token = strtok(NULL, "\t");
char *fnout = malloc(strlen(id)+5);
fnout = strcat(fnout, id);
fnout = strcat(fnout, ".seq");
fpout = fopen(fnout, "w");
setvbuf ( fpout , NULL , _IONBF , 0 );
fprintf(fpout, "%s", token);
fclose(fpout);
}
fclose(fp);
return 0;
}
C ++
İyi performans gösterir ve yazmak gerçek C'den çok daha kolaydır. Bütün bunlar mantığı basitleştirebileceğiniz anlamına gelir. strtok
C bir domuz, çünkü tüm dizeyi işler ve sonra o yorucu bellek ayırma yapmak gerekir. Bu sekmeye çarpana kadar çizgi boyunca kayar ve segmentleri ihtiyacımız olduğu kadar dışarı çekeriz.
#include <fstream>
#include <string>
using namespace std;
int main(void) {
ifstream in("infile");
ofstream out;
string line;
while(getline(in, line)) {
string::size_type tab = line.find('\t', 0);
string filename = line.substr(0, tab) + ".seq";
out.open(filename.c_str());
out << line.substr(tab + 1);
out.close();
}
in.close();
}
GNU Paralel
(Moreutils sürümü değil). Güzel bir özlü sözdizimi ama OMGSLOW. Yanlış kullanıyor olabilirim.
parallel --colsep '\t' echo {2} \> {1}.seq <infile
Test kablo demeti jeneratörü
İşte 100000 satırlık [ATGC] * 64 için veri oluşturucum. Hızlı değil ve gelişmeler çok açıktır.
cat /dev/urandom | tr -dc 'ATGC' | fold -w 64 | awk 'NR>100000{exit}{printf NR"\t"$0"\n"}' > infile
awk
on milyondan az bir şey için hala iyi bir cevap. Bunu [lineer olarak] bir milyar satıra kadar ölçeklendirseniz bile, C sizi Perl'den sadece 1.5 saat ve awk'den 3.6 saat tasarruf ediyor.