ACHTUNG. Das ist ein Archiv des alten forum.ruby-portal.de. Die aktuelle Mailingliste gibt es auf lists.ruby-lang.org/pipermail/ruby-de.

NOTICE. This is a ready-only copy of the old forum.ruby-portal.de. You can find the current mailing list at lists.ruby-lang.org/pipermail/ruby-de.

Die Programmiersprache Ruby

Blog|

Forum|

Wiki  


Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]

Ein neues Thema erstellen Auf das Thema antworten  [ 10 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Dir.glob speedup?
BeitragVerfasst: 26 Jun 2011, 09:46 
Offline
Schüler

Registriert: 11 Okt 2010, 17:54
Beiträge: 36
Hallo Leute,

folgendes: ich schreibe (wie vielleicht schon bekannt ist) einen Musikplayer in pure Ruby. Es stellt sich jetzt folgendes "Problemchen": Ich lese die Musiksammlung mit



Dir.glob("**/**")

Um das ganze dann in die Datenbank zu bringen (DataMapper).

Allerdings ist das selbst bei noch relativ kleinen Musiksammlungen (meine hat ca 25.000 Titel) schon relativ langsam, weswegen ich überlege, wie man das ganze verschnellern könnte.
Erste Überlegung die ich so hatte war, Threads für Unterordner rennen zu lassen. Allerdings läuft (soweit mir bekannt ist? ) Ruby sowieso nur auf einem Kern, weswegen das vielleicht garnix bringt?

Hat da jemand Ideen?

musicmatze


Nach oben
 Profil  
 
 Betreff des Beitrags: Re: Dir.glob speedup?
BeitragVerfasst: 26 Jun 2011, 10:28 
Offline
Interpreter
Benutzeravatar

Registriert: 18 Sep 2008, 22:32
Beiträge: 1821
Wohnort: NRW → UN
Vielleicht kannst du das Find-Modul (stdlib) gebrauchen?



1
2
3
4
require "find"
Find.find do |path|
puts path
end


Das iteriert rekursiv über den gesamten Verzeichnisbaum ab dem aktuellen Arbeitsverzeichnis, wenn du von einem anderen Verzeichnis starten willst, kannst du das Find.find als Argument mitgeben. Wenn du ein Verzeichnis auslassen willst, kannst du in dessen Iteration Find.prune aufrufen. → http://www.ruby-doc.org/stdlib/libdoc/find/rdoc/classes/Find.html
Vorteil gegenüber Dir.glob: Es wird nicht alles auf einmal in den Speicher gelesen, sondern nur eine Datei pro Iteration (nehme ich jedenfalls an).

Vale,
Quintus

_________________
Habe den Mut, dich deines eigenen Verstandes zu bedienen! — Immanuel Kant

Ich bin freischaffender Softwareentwickler und freue mich über jedes neue Projekt. Kontaktinformation auf meiner Website.

Mein Blog | GitHub-Profil | Auf Twitter: @qquintilianus | PGP/GPG-Schlüssel: B1FE 958E D5E8 468E AA20 8F4B F1D8 799F BCC8 BC4F


Nach oben
 Profil  
 
 Betreff des Beitrags: Re: Dir.glob speedup?
BeitragVerfasst: 26 Jun 2011, 12:28 
Offline
Schüler

Registriert: 11 Okt 2010, 17:54
Beiträge: 36
leider, leider zeigt mir benchmark:


1
2
024:00>> Benchmark.measure { Find.find( "./tmp/" ) do |x| end } #=>   0.300000   0.150000   0.450000 (  0.831742)
025:00>> Benchmark.measure { Dir.glob( "./tmp/**/**") } #=> 0.060000 0.100000 0.160000 ( 0.173796)


Natürlich hab ich auch dafür gesorgt, dass das was ich anguck schon im speicher liegt.


Nach oben
 Profil  
 
 Betreff des Beitrags: Re: Dir.glob speedup?
BeitragVerfasst: 28 Jun 2011, 08:43 
Offline
ri
Benutzeravatar

Registriert: 08 Apr 2006, 17:03
Beiträge: 788
Wohnort: Berlin
Gefühlsmäßig würde ich sagen, Threads bringen da nicht viel Geschwindigkeitsgewinn, da du ja, so wie ich das verstehe, sowieso auf das Einlesen aller Einträge warten willst. Im wesentlichen teilst du dann eine große Aufgabe nur in viele kleine Aufgaben auf, nutzt aber nicht die eigentlichen Vorteile einer Parallelisierung. Ideal wären Threads beispielsweise, wenn du die Titel von verschiedenen Hosts irgendwo im Netz holen würdest - da würden Threads Vorteile ggü. einer sequentiellen Lösung bieten.

Aber mal was anderes: Mußt du denn diese 25000 Einträge bei jedem Programmstart einlesen? Würde es nicht genügen, diese Titel in einer Datenbank zu haben und beim Programmstart oder regelmäßig in bestimmenten zeitlichen Abständen nachzusehen, ob neue, noch nicht in der DB vorhandene Einträge existieren? Das wiederum wäre eine ideale Aufgabe, um mit Threads zu arbeiten.

-Thomas

_________________
"Programs must be written for people to read, and only incidentally
for machines to execute."
- H. Abelson and G. Sussman
(in "The Structure and Interpretation of Computer Programs)


Nach oben
 Profil  
 
 Betreff des Beitrags: Re: Dir.glob speedup?
BeitragVerfasst: 28 Jun 2011, 10:29 
Offline
Interpreter
Benutzeravatar

Registriert: 03 Jul 2006, 14:53
Beiträge: 4872
Wohnort: RLP
Eine Frage habe ich noch: bist du sicher, dass der Dateizugriff der Bottleneck ist und nicht der Datenbankzugriff? (Ich weiss ja nicht, welche DB du verwendest).

Gruß,
Skade


Nach oben
 Profil  
 
 Betreff des Beitrags: Re: Dir.glob speedup?
BeitragVerfasst: 20 Jul 2011, 11:23 
Offline
Schüler

Registriert: 11 Okt 2010, 17:54
Beiträge: 36
Skade hat geschrieben:
Eine Frage habe ich noch: bist du sicher, dass der Dateizugriff der Bottleneck ist und nicht der Datenbankzugriff? (Ich weiss ja nicht, welche DB du verwendest).

Gruß,
Skade


Nunja, zur Zeit arbeite ich noch mit SQLite, bin aber gerade im begriff, auf mysql einzustellen (was dank DataMapper ja kein Problem ist). Zum verständniss: Es soll beim Musikplayer später dem User überlassen bleiben, ob er SQLite oder Msql (oder *) verwendet.

thopre hat geschrieben:
[...]
Aber mal was anderes: Mußt du denn diese 25000 Einträge bei jedem Programmstart einlesen? Würde es nicht genügen, diese Titel in einer Datenbank zu haben und beim Programmstart oder regelmäßig in bestimmenten zeitlichen Abständen nachzusehen, ob neue, noch nicht in der DB vorhandene Einträge existieren? Das wiederum wäre eine ideale Aufgabe, um mit Threads zu arbeiten.

-Thomas


Selbstverständlich läuft es so ab. Der User kann praktisch sagen "Hey, hier is meine Sammlung drunter <pfad>, Scan das mal ab." und dann rutscht das ganze in die Datenbank.


Nach oben
 Profil  
 
 Betreff des Beitrags: Re: Dir.glob speedup?
BeitragVerfasst: 20 Jul 2011, 15:31 
Offline
Interpreter
Benutzeravatar

Registriert: 03 Jul 2006, 14:53
Beiträge: 4872
Wohnort: RLP
musicmatze hat geschrieben:
Skade hat geschrieben:
Eine Frage habe ich noch: bist du sicher, dass der Dateizugriff der Bottleneck ist und nicht der Datenbankzugriff? (Ich weiss ja nicht, welche DB du verwendest).

Gruß,
Skade


Nunja, zur Zeit arbeite ich noch mit SQLite, bin aber gerade im begriff, auf mysql einzustellen (was dank DataMapper ja kein Problem ist). Zum verständniss: Es soll beim Musikplayer später dem User überlassen bleiben, ob er SQLite oder Msql (oder *) verwendet.


Naja, gerade bei SQLite ist ja die Frage, wie genau du darauf zugreifst (Batch-Weise, einzeln, etc.). Und Threads werden dir dann wahrscheinlich auch nicht soviel bringen, weil auf SQLite immer nur ein Thread gleichzeitig schreiben kann.

Gruß,
Skade


Nach oben
 Profil  
 
 Betreff des Beitrags: Re: Dir.glob speedup?
BeitragVerfasst: 29 Jul 2011, 07:24 
Offline
Novize
Benutzeravatar

Registriert: 04 Okt 2010, 09:44
Beiträge: 19
Kann mich @Skade nur anschließen - denke auch, dass der "Hund" in der Art und Weise wie du deine Daten in die DB schreibst "begraben liegt".

Irgendwie geht mir hier die Größenordnung noch ab - wie lange dauert es aktuell, was passiert dazwischen und was ist das SOLL?

(Ich hatte bei einem thematisch verwandten Projekt, eher das Öffnen der File-Handles und Auslesen der einzelnen Mp3-Tags als "Bottle-Neck" ausgemacht ... die Zeit für die Auffindung der Audio-Files mit glob / find war eigentlich vernachlässigbar.)

mfg Joker


Nach oben
 Profil  
 
 Betreff des Beitrags: Re: Dir.glob speedup?
BeitragVerfasst: 29 Jul 2011, 18:25 
Offline
ri
Benutzeravatar

Registriert: 08 Apr 2006, 17:03
Beiträge: 788
Wohnort: Berlin
musicmatze hat geschrieben:
thopre hat geschrieben:
[...]
Aber mal was anderes: Mußt du denn diese 25000 Einträge bei jedem Programmstart einlesen? Würde es nicht genügen, diese Titel in einer Datenbank zu haben und beim Programmstart oder regelmäßig in bestimmenten zeitlichen Abständen nachzusehen, ob neue, noch nicht in der DB vorhandene Einträge existieren? Das wiederum wäre eine ideale Aufgabe, um mit Threads zu arbeiten.

-Thomas


Selbstverständlich läuft es so ab. Der User kann praktisch sagen "Hey, hier is meine Sammlung drunter <pfad>, Scan das mal ab." und dann rutscht das ganze in die Datenbank.


Das halte ich aber für eine sehr umständliche Vorgehensweise. Du liest jedesmal 25000 Einträge neu in die DB ein, nur weil vielleicht ein einziger neuer Titel dazugekommen ist? Warum das ganze nicht in der DB vorhalten?

-Thomas

_________________
"Programs must be written for people to read, and only incidentally
for machines to execute."
- H. Abelson and G. Sussman
(in "The Structure and Interpretation of Computer Programs)


Nach oben
 Profil  
 
 Betreff des Beitrags: Re: Dir.glob speedup?
BeitragVerfasst: 15 Okt 2011, 02:02 
Offline
Nuby

Registriert: 20 Dez 2009, 23:54
Beiträge: 2
Ich weiß, der Thread ist schon ein paar Tage alt. Aber falls jemand doch mal (wie ich heute) genau das selbe Problem haben sollte:

Es macht wirklich einen riesigen Unterschied wie man in sqlite3 schreibt:

Zitat:
[bofh@thor dev]$ ruby sqlite_test.rb
5393 files where added to the database
This run took 527.642683746 sec.
[bofh@thor dev]$ rm test.db
[bofh@thor dev]$ ruby sqlite_test_opt.rb
5393 files where added to the database
This run took 2.800191847 sec.



sqlite_test.rb:
Zitat:
require 'find'
require 'sqlite3'

start = Time.now
db = SQLite3::Database.new("./test.db")
db.execute("CREATE TABLE IF NOT EXISTS Files(column1 varchar(256))")

count = 0

Find.find("/home/bofh") do | path |
next if path =~ /'/
count += 1
db.execute("INSERT INTO Files VALUES('#{path}')")
end

stop = Time.now
rtime = stop - start
puts "#{count} files where added to the database"
puts "This run took #{rtime} sec."


sqlite_test_opt.rb:
Zitat:
require 'find'
require 'sqlite3'

start = Time.now
db = SQLite3::Database.new("./test.db")
db.execute("CREATE TABLE IF NOT EXISTS Files(column1 varchar(256))")

a = []
count = 0

Find.find("/home/bofh") do | path |
next if path =~ /'/
count += 1
a.push(path)
end

statement = "BEGIN TRANSACTION; INSERT INTO Files VALUES("
count1 = 1
a.each do | path |
statement += "'#{path}'"
if count1 < a.length
statement += ","
else
statement += "); COMMIT;"
end
count1 += 1
end
db.execute(statement)

stop = Time.now
rtime = stop - start
puts "#{count} files where added to the database"
puts "This run took #{rtime} sec."


Ist jetzt nicht besonders sauber, sondern nur zu Testzwecken dahingehackt, aber ich denke es illustriert ganz gut dass man je nach dem wie man in sqlite3 schreibt noch richtig was rausholen kann. Ich war überrascht dass es so viel ist.


Nach oben
 Profil  
 
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 10 Beiträge ] 

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
cron