Erweiterung der Antwort von Dejw (edit2):
File.open(filename,'w'){ |f|
uri = URI.parse(url)
Net::HTTP.start(uri.host,uri.port){ |http|
http.request_get(uri.path){ |res|
res.read_body{ |seg|
f << seg
#hack -- adjust to suit:
sleep 0.005
}
}
}
}
wo filename
undurl
sind Saiten.
Der sleep
Befehl ist ein Hack, der die CPU-Auslastung drastisch reduzieren kann, wenn das Netzwerk der begrenzende Faktor ist. Net :: HTTP wartet nicht darauf, dass der Puffer (16 KB in Version 1.9.2) gefüllt wird, bevor er nachgibt, sodass die CPU selbst kleine Teile bewegt. Wenn Sie einen Moment lang schlafen, kann sich der Puffer zwischen den Schreibvorgängen füllen, und die CPU-Auslastung ist vergleichbar mit einer Curl-Lösung, die sich in meiner Anwendung um das 4-5-fache unterscheidet. Eine robustere Lösung könnte den Fortschritt von untersuchenf.pos
und das Zeitlimit anpassen, um beispielsweise 95% der Puffergröße zu erreichen - tatsächlich habe ich in meinem Beispiel die 0,005-Zahl erhalten.
Entschuldigung, aber ich kenne keine elegantere Möglichkeit, Ruby warten zu lassen, bis sich der Puffer gefüllt hat.
Bearbeiten:
Dies ist eine Version, die sich automatisch anpasst, um den Puffer auf oder unter der Kapazität zu halten. Es ist eine unelegante Lösung, aber es scheint genauso schnell zu sein und so wenig CPU-Zeit zu verbrauchen, wie es zum Locken aufruft.
Es funktioniert in drei Stufen. Eine kurze Lernphase mit einer absichtlich langen Schlafzeit legt die Größe eines vollen Puffers fest. Die Drop-Periode reduziert die Ruhezeit bei jeder Iteration schnell, indem sie mit einem größeren Faktor multipliziert wird, bis ein unterfüllter Puffer gefunden wird. Während der normalen Zeit wird es dann um einen kleineren Faktor nach oben und unten angepasst.
Mein Ruby ist etwas rostig, daher bin ich mir sicher, dass dies verbessert werden kann. Erstens gibt es keine Fehlerbehandlung. Vielleicht könnte es auch in ein Objekt getrennt werden, weg vom Herunterladen selbst, so dass Sie einfach autosleep.sleep(f.pos)
in Ihrer Schleife aufrufen würden ? Noch besser ist, dass Net :: HTTP geändert werden könnte, um auf einen vollen Puffer zu warten, bevor es ergibt :-)
def http_to_file(filename,url,opt={})
opt = {
:init_pause => 0.1, #start by waiting this long each time
# it's deliberately long so we can see
# what a full buffer looks like
:learn_period => 0.3, #keep the initial pause for at least this many seconds
:drop => 1.5, #fast reducing factor to find roughly optimized pause time
:adjust => 1.05 #during the normal period, adjust up or down by this factor
}.merge(opt)
pause = opt[:init_pause]
learn = 1 + (opt[:learn_period]/pause).to_i
drop_period = true
delta = 0
max_delta = 0
last_pos = 0
File.open(filename,'w'){ |f|
uri = URI.parse(url)
Net::HTTP.start(uri.host,uri.port){ |http|
http.request_get(uri.path){ |res|
res.read_body{ |seg|
f << seg
delta = f.pos - last_pos
last_pos += delta
if delta > max_delta then max_delta = delta end
if learn <= 0 then
learn -= 1
elsif delta == max_delta then
if drop_period then
pause /= opt[:drop_factor]
else
pause /= opt[:adjust]
end
elsif delta < max_delta then
drop_period = false
pause *= opt[:adjust]
end
sleep(pause)
}
}
}
}
end