Memperluas jawaban 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
}
}
}
}
dimana filename
dan url
string.
The sleep
perintah adalah hack yang dapat secara dramatis mengurangi penggunaan CPU ketika jaringan adalah faktor pembatas. Net :: HTTP tidak menunggu buffer (16kB dalam v1.9.2) untuk diisi sebelum menghasilkan, sehingga CPU sibuk memindahkan potongan-potongan kecil. Tidur sebentar memberikan buffer kesempatan untuk mengisi antara menulis, dan penggunaan CPU sebanding dengan solusi keriting, perbedaan 4-5x dalam aplikasi saya. Solusi yang lebih kuat mungkin memeriksa kemajuan f.pos
dan menyesuaikan batas waktu untuk menargetkan, katakanlah, 95% dari ukuran buffer - sebenarnya itulah cara saya mendapatkan angka 0,005 dalam contoh saya.
Maaf, tapi saya tidak tahu cara yang lebih elegan untuk membuat Ruby menunggu buffer untuk mengisi.
Edit:
Ini adalah versi yang secara otomatis menyesuaikan diri untuk menjaga buffer hanya pada atau di bawah kapasitas. Ini adalah solusi yang tidak bagus, tetapi tampaknya sama cepatnya, dan menggunakan waktu CPU sesedikit mungkin, karena itu memanggil untuk mengeriting.
Ini bekerja dalam tiga tahap. Suatu periode pembelajaran singkat dengan waktu tidur yang sengaja panjang menetapkan ukuran buffer penuh. Periode drop mengurangi waktu tidur dengan cepat dengan setiap iterasi, dengan mengalikannya dengan faktor yang lebih besar, sampai menemukan buffer yang kurang terisi. Kemudian, selama periode normal, itu menyesuaikan atas dan ke bawah oleh faktor yang lebih kecil.
Ruby saya agak berkarat, jadi saya yakin ini bisa diperbaiki. Pertama-tama, tidak ada penanganan kesalahan. Juga, mungkin itu bisa dipisahkan menjadi objek, jauh dari pengunduhan itu sendiri, sehingga Anda hanya perlu menelepon autosleep.sleep(f.pos)
di loop Anda? Bahkan lebih baik, Net :: HTTP dapat diubah untuk menunggu buffer penuh sebelum menghasilkan :-)
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