2016-09-22 2 views
3

파이썬을 사용하여 멀티 스레드 다운로더를 만들려고합니다. 내가 크기 100MB의 비디오에 대한 링크를 가지고 있고, 각 스레드가 20MB를 동시에 다운로드하면서 5 개의 스레드를 사용하여 다운로드하려고한다고 가정 해 봅시다. 그런 일이 생기려면 초기 응답을 파일의 다른 부분 (예 : 0-20MB, 20-40MB, 40-60MB, 60-80MB, 80-100MB)을 나타내는 5 부분으로 나누어야하며, http를 검색하고 찾았습니다 범위 헤더가 도움이 될 수 있습니다. 다음은 샘플 코드http 응답을 청크로 나누는 방법은 무엇입니까?

from urllib.request import urlopen,Request 
url= some video url 
header = {'Range':'bytes=%d-%d' % (5000,10000)} # trying to capture all the bytes in between 5000th and 1000th byte. 
req=Request(url,headers=header) 
res=urlopen(req) 
r=res.read() 

이다 그러나 위의 코드는 내가 원하는 바이트 대신 전체 비디오를 읽고 그것을 명확하게 작동하지 않습니다. 그렇다면 처음부터 읽는 대신 동영상의 특정 부분에서 지정한 바이트 범위를 읽을 수있는 방법이 있습니까? 간단한 말로 설명하십시오.

+0

병목 현상이 연결 대역폭 인 경우 멀티 스레딩을 사용하면 더 빨리 작업을 수행하지 못할 수도 있습니다. – martineau

+0

제목에 대해 [_Byte serving_] (https://en.wikipedia.org/wiki/Byte_serving)이라는 Wikipedia 기사를 참조하십시오. 응답의'Content-Range' 헤더는 어떤 바이트가 전달되는지 알려줍니다. – martineau

+0

예, 동의합니다. 나는 그것을 시험해보고 싶다. – Airbear

답변

1

위의 코드는 바이트 대신 전체 비디오를 읽으므로 분명히 작동하지 않습니다.

핵심 문제는 기본 요청이 한 번에 전체 파일을 아래로 당기는 HTTP GET 방법을 사용합니다.

request.get_method = lambda : 'HEAD'을 추가하여 수정할 수 있습니다. 이 경우 HTTP HEAD 메서드를 사용하여 Content-Length을 가져오고 범위 요청보다 지원되는지 확인합니다.

다음은 청크 요청의 작동 예입니다. 그냥 관심의 URL로 URL을 변경

from urllib.request import urlopen, Request 

url = 'http://www.jython.org' # This is an example. Use your own url here. 

n = 5 
request = Request(url) 
request.get_method = lambda : 'HEAD' 
r = urlopen(request) 

# Verify that the server supports Range requests 
assert r.headers.get('Accept-Ranges', '') == 'bytes', 'Range requests not supported' 

# Compute chunk size using a double negation for ceiling division 
total_size = int(r.headers.get('Content-Length')) 
chunk_size = -(-total_size // n) 

# Showing chunked downloads. This should be run in multiple threads. 
chunks = [] 
for i in range(n): 
    start = i * chunk_size 
    end = start + chunk_size - 1 # Bytes ranges are inclusive 
    headers = dict(Range = 'bytes=%d-%d' % (start, end)) 
    request = Request(url, headers=headers) 
    chunk = urlopen(request).read() 
    chunks.append(chunk) 

별도 요청을위한 루프에서 병렬로 사용하여 스레드 또는 프로세스에서 수행 할 수 있습니다. 인터넷에 여러 개의 실제 연결이있는 환경에서 실행하면 속도가 향상됩니다. 그러나 물리적 연결이 하나만있는 경우 병목 현상이 발생할 수 있으므로 병렬 요청이 예상 한만큼 도움이되지 않습니다.

+0

오프 주제 :'chunk_size = - (- total_size // n)'에 대한 코멘트는 꽤 쓸모가 없습니다. ** _ 왜 _ ** 이렇게하는거야? – martineau

+0

@martineau 위의 설명에 설명되어 있습니다. 이중 부정은 "천장 구분"을 계산합니다. * total_size *가 1602이고 * n *이 4 인 경우 전체 데이터 집합을 포함하지 않는 400 (바닥 나누기)이 아닌 * chunk_size *가 401 (천장 분할)이되어야합니다 (400 * 4 <1602 < = 401 * 4). –

관련 문제