U
Unregistriert
Gast
Hi Leute!
Das soll kein Allgemeiner Java ist schneller/langsamer als Sprache X Flamewar werden! Ich verarbeite auf einem Hochleistungsrechner riesengrosse Inputdateien. Da ich zwischen den Durchlaeufen meines Programmes immer wieder viel Wartezeit hab, hab ich mir gedacht ich schreib das gleiche Programm mal in mehreren Sprachen, um zu sehen ob sichs wirklich lohnt, dass ich das ganze in C++ implementiert hab, oder ob ichs genauso gut in einer Sprache haette schreiben koennen, die weniger lowlevel ist. Da ich aber schon laenger kein Java geschrieben hab, hab ich mir gedacht ich frag mal hier nach ob irgendwer interessiert ist eine optimierte Version des Programms zu schreiben, deren Zeitverbrauch ich dann messen kann. Ist zwar ein Microbenchmark, aber immerhin ein realworld Problem
Folgende Aufgabestellung:
In einem Verzeichnis finden sich viele Unterverzeichnisse, die mit "B" anfangen. In (fast!) jedem dieser Unterverzeichnisse liegt eine Datei names "out.gz". Das sind gz-komprimierte Dateien, die Zeilen der folgenden Art enthalten:
d.h. als Regex schaut die Zeile wie folgt aus: r\d+_\d+\s(+|-)\schr\d+\s\d+(.*)
Aus jeder Zeile muss ich die Zahl gleich nach dem chr (die liegt immer zwischen 1 und 22 inklusive) sowie die darauffolgende, laengere Zahl extrahieren. Dann muss ich zaehlen, bei wievielen Zahlen Zahl 1 einem bestimmten Wert entspricht und Zahl 2 in einem bestimmten Bereich liegt. Diese Anzahl soll dann (fuer jede Datei) auf der Konsole ausgegeben werden. Nichts anderes soll ausgegeben werden.
Ich habe das Programm bisher in C++ sowie in Perl implementiert. Beide Implementierungen bearbeiten jeweils 24 Dateien auf einmal (in entsprechenden Threads). Ausserdem verwenden beide das Unix-Programm 'zcat' zum Entpacken der gz-Datei -- auf dem Rechner, auf dem ich die Zeit messe, darf ich 32 Rechenkerne verwenden, also darf paralellisiert werden.
Ich spar euch meine C++ Implementierung, in Perl schaut das ganze wie folgt aus:
Die Perl-Version benoetigt 10 Stunden, um alle Dateien zu verarbeiten, C++ schaffts in 2. Mich wuerds interessieren, wie schnell eine ordentlich geschriebene Java-Version ist. Wenn das sonst noch wen interessieren bin ich gespannt auf eure Loesungen
Das soll kein Allgemeiner Java ist schneller/langsamer als Sprache X Flamewar werden! Ich verarbeite auf einem Hochleistungsrechner riesengrosse Inputdateien. Da ich zwischen den Durchlaeufen meines Programmes immer wieder viel Wartezeit hab, hab ich mir gedacht ich schreib das gleiche Programm mal in mehreren Sprachen, um zu sehen ob sichs wirklich lohnt, dass ich das ganze in C++ implementiert hab, oder ob ichs genauso gut in einer Sprache haette schreiben koennen, die weniger lowlevel ist. Da ich aber schon laenger kein Java geschrieben hab, hab ich mir gedacht ich frag mal hier nach ob irgendwer interessiert ist eine optimierte Version des Programms zu schreiben, deren Zeitverbrauch ich dann messen kann. Ist zwar ein Microbenchmark, aber immerhin ein realworld Problem
Folgende Aufgabestellung:
In einem Verzeichnis finden sich viele Unterverzeichnisse, die mit "B" anfangen. In (fast!) jedem dieser Unterverzeichnisse liegt eine Datei names "out.gz". Das sind gz-komprimierte Dateien, die Zeilen der folgenden Art enthalten:
Code:
r0000000002_0000013 + chr5 15066603
r0000000002_0000013 + chr16 83182741
r0000000002_0000013 + chr2 143804139
r0000000002_0000013 + chr2 37058717
r0000000002_0000013 + chr9 129767214
r0000000002_0000013 + chr8 95742116
r0000000002_0000013 + chr13 26811053
r0000000002_0000013 + chr6 126964211
r0000000002_0000013 + chr13 99652112
r0000000002_0000013 + chr13 20842317
r0000000082_0000001 - chr2 132519799 27:T>N
r0000000082_0000001 - chr12 12822087 27:T>N
r0000000082_0000001 - chr18 27977283 27:T>N
r0000000082_0000001 - chr16 2737473 27:T>N
d.h. als Regex schaut die Zeile wie folgt aus: r\d+_\d+\s(+|-)\schr\d+\s\d+(.*)
Aus jeder Zeile muss ich die Zahl gleich nach dem chr (die liegt immer zwischen 1 und 22 inklusive) sowie die darauffolgende, laengere Zahl extrahieren. Dann muss ich zaehlen, bei wievielen Zahlen Zahl 1 einem bestimmten Wert entspricht und Zahl 2 in einem bestimmten Bereich liegt. Diese Anzahl soll dann (fuer jede Datei) auf der Konsole ausgegeben werden. Nichts anderes soll ausgegeben werden.
Ich habe das Programm bisher in C++ sowie in Perl implementiert. Beide Implementierungen bearbeiten jeweils 24 Dateien auf einmal (in entsprechenden Threads). Ausserdem verwenden beide das Unix-Programm 'zcat' zum Entpacken der gz-Datei -- auf dem Rechner, auf dem ich die Zeit messe, darf ich 32 Rechenkerne verwenden, also darf paralellisiert werden.
Ich spar euch meine C++ Implementierung, in Perl schaut das ganze wie folgt aus:
Java:
#/usr/bin/perl
use strict;
use threads;
use threads::shared;
use Fcntl ':mode';
my @dirs : shared;
sub process($)
{
my $dir = shift;
my $target_chr = 6;
my $target_start = 110000000;
my $target_end = 110001000;
my $cnt = 0;
open(my $input, "zcat $dir/out.gz |") or die "open() failed on $dir: $!";
while (<$input>)
{
/chr(\d+)\s+(\d+)/;
my ($chr, $start) = ($1, $2);
if ($chr == $target_chr && $target_start <= $start && $start < $target_end)
{
++$cnt;
}
}
close($input);
return $cnt;
}
sub threadmain()
{
my $dir;
my $cnt;
while (1)
{
{
lock(@dirs);
return if ($#dirs == -1);
$dir = shift(@dirs);
}
$cnt = process($dir);
# make sure only one thread is writing!
{
lock(@dirs);
print $cnt;
}
}
}
my $dir;
while ($dir = </bioinf_ag/data/hapmapSeq/B*>)
{
my @stat = stat($dir);
next if (!S_ISDIR($stat[2]));
# print "$dir\n";
push(@dirs, $dir);
}
my $num_threads = 24;
my @threads;
for (my $i = 0; $i < $num_threads; ++$i)
{
push(@threads, threads->create(\&threadmain));
}
foreach my $t (@threads)
{
$t->join();
}
Die Perl-Version benoetigt 10 Stunden, um alle Dateien zu verarbeiten, C++ schaffts in 2. Mich wuerds interessieren, wie schnell eine ordentlich geschriebene Java-Version ist. Wenn das sonst noch wen interessieren bin ich gespannt auf eure Loesungen