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
}
}
}
}
어디에 filename
그리고 url
문자열입니다.
이 sleep
명령은 네트워크가 제한 요인 일 때 CPU 사용량을 크게 줄일 수있는 해킹입니다 . Net :: HTTP는 버퍼 (v1.9.2의 16kB)가 가득 찰 때까지 기다리지 않으므로 CPU는 자체적으로 작은 덩어리를 움직입니다. 잠을 자면 버퍼가 쓰기 사이를 채울 수 있으며 CPU 사용량은 응용 프로그램의 4-5 배 차이 인 컬 솔루션과 비슷합니다. 더 강력한 솔루션은 진행률을 검사 f.pos
하고 버퍼 크기의 95 %를 목표로 시간 초과를 조정할 수 있습니다 . 실제로 예제에서 0.005 숫자를 얻었습니다.
죄송하지만 Ruby가 버퍼가 가득 찰 때까지 기다리는 더 우아한 방법을 모르겠습니다.
편집하다:
이것은 버퍼를 용량 이하로 유지하기 위해 자동으로 조정되는 버전입니다. 우아하지 않은 솔루션이지만 컬링을 부르는 것처럼 빠르며 CPU 시간을 적게 사용하는 것 같습니다.
세 단계로 작동합니다. 의도적으로 긴 수면 시간을 갖는 짧은 학습 기간은 전체 버퍼의 크기를 설정합니다. 드롭 기간은 언더필 버퍼를 찾을 때까지 더 큰 계수를 곱하여 각 반복마다 슬립 시간을 빠르게 줄입니다. 그런 다음 정상 기간 동안 더 작은 계수만큼 위아래로 조정됩니다.
내 루비는 조금 녹슬 었으므로 개선 될 수 있다고 확신합니다. 우선, 오류 처리가 없습니다. 또한 다운로드 자체와는 별도로 객체로 분리되어 autosleep.sleep(f.pos)
루프를 호출 할 수 있습니까? 더 좋은 점은 Net :: HTTP가 전체 버퍼를 기다리도록 변경하여
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