Développement sur la réponse de 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
}
}
}
}
où filename
eturl
sont des chaînes.
La sleep
commande est un hack qui peut réduire considérablement l'utilisation du processeur lorsque le réseau est le facteur limitant. Net :: HTTP n'attend pas que le tampon (16 Ko dans la v1.9.2) se remplisse avant de céder, donc le processeur s'emploie à déplacer de petits morceaux. Dormir pendant un moment donne au tampon une chance de se remplir entre les écritures, et l'utilisation du processeur est comparable à une solution curl, différence 4-5x dans mon application. Une solution plus robuste pourrait examiner les progrèsf.pos
et ajuster le délai d'expiration pour cibler, par exemple, 95% de la taille de la mémoire tampon - en fait, c'est ainsi que j'ai obtenu le nombre 0,005 dans mon exemple.
Désolé, mais je ne connais pas une manière plus élégante de faire attendre Ruby que le tampon se remplisse.
Éditer:
Il s'agit d'une version qui s'ajuste automatiquement pour garder le tampon juste à sa capacité ou en dessous. C'est une solution inélégante, mais elle semble être tout aussi rapide et utiliser aussi peu de temps CPU, car elle appelle à curl.
Cela fonctionne en trois étapes. Une brève période d'apprentissage avec un temps de sommeil délibérément long détermine la taille d'un tampon plein. La période de suppression réduit rapidement le temps de sommeil à chaque itération, en le multipliant par un facteur plus grand, jusqu'à ce qu'il trouve un tampon sous-rempli. Ensuite, pendant la période normale, il s'ajuste vers le haut et vers le bas par un facteur plus petit.
Mon Ruby est un peu rouillé, donc je suis sûr que cela peut être amélioré. Tout d'abord, il n'y a pas de gestion des erreurs. Aussi, peut-être qu'il pourrait être séparé en un objet, loin du téléchargement lui-même, de sorte que vous l'appeliez simplement autosleep.sleep(f.pos)
dans votre boucle? Mieux encore, Net :: HTTP pourrait être modifié pour attendre un tampon plein avant de céder :-)
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