당신은 효과적으로 파일 청크의 반복자를 통해 sha256.update를 매핑 할 . 기본적으로 map
이 반복을 대체했습니다.
장애물은 전체 파일을 메모리로로드하는 (아마도) read_those_chunks
을 피하기위한 것입니다.
def read_those_chunks(open_file, chunk_size):
offset = 0
while True:
yield open_file.readChunk(offset, chunk_size)
offset += chunk_size
이후의 덩어리 (또는 EOFError
)와 함께 화재 Deferred
의를 산출 발전기가있다 : 그래서, 첫 번째 단계로, 그 조각을 구현한다. 죄송 합니다만 map
과 함께 사용할 수 없습니다. , async_map
여전히 우리가에서 모든 덩어리를 방문하여 확인 할 책임이 async_map
이후
def async_map(function, iterable):
try:
d = next(iterable)
except StopIteration:
return
d.addCallback(function)
d.addCallback(lambda ignored: async_map(function, iterable))
return d
이 map
을 대체 할 것입니다 및 map
원래 구현에서 반복을 교체 : 그래서 지금은지도 표시 - 동일 조건 변경 허락이 처리 할 수 구현 반복 가능. 그러나 반복 (for
또는 while
)은 Deferred
과 잘 섞이지 않습니다 (일반적으로 혼합하는 것은 inlineCallbacks
일 때입니다). 따라서 async_map
은 반복하지 않습니다. 재발 - 일반적인 반복 대안. 각각의 재귀 호출은 더 이상 존재하지 않을 때까지 (또는이 경우 EOFError
로 인해 발생하는 Deferred
이 실패 할 때까지) 반복 가능 프로그램의 다음 요소에서 작동합니다.
재귀는 함수 및 함수 호출에서 작동하기 때문에 Deferred
을 사용한 반복보다 잘 작동합니다. Deferred
은 함수 및 함수 호출을 처리 할 수 있습니다. 함수를 addCallback
및 Deferred
으로 전달하면 결국 해당 함수가 호출됩니다. 반복은 함수의 작은 조각 ("블록"또는 "스위트"라고도 함)과 Deferred
으로 처리 할 수 없습니다. 블록을 addCallback
에 보낼 수 없습니다.
는 이제 Deferred
을 만들려면 다음 두 가지를 사용하는 화재 다이제스트 계산했을 때 : 또한 async_map
그것의 결과 목록을 생성하지 않는다는에 map
과 다른 것을 알 수 있습니다
def calculate_checksum(open_file, chunk_size):
hasher = hashlib.sha256()
chunks = read_those_chunks(open_file, chunk_size)
d = async_map(hasher.update, chunks)
d.addErrback(lambda err: err.trap(EOFError))
d.addCallback(lambda ignored: hasher.hexdigest())
return d
함수 호출을 만듭니다. 아마도 그것은 더 reduce
같다 :
는
def async_reduce(function, iterable, lhs):
try:
d = next(iterable)
except StopIteration:
return lhs
d.addCallback(lambda rhs: function(lhs, rhs))
d.addCallback(lambda lhs: async_reduce(function, iterable, lhs))
return d
은 물론, 여전히 대신 반복의 순환이다.
는 그리고 hexdigest을 계산하는 감소 함수 같다 :
def update_hash(hasher, s):
hasher.update(s)
return hasher
그리고 calculate_checksum
이된다 다음 hasher
클로저를 구비하지 않는 비트 좋네요
def calculate_checksum(open_file, chunk_size):
chunks = read_those_chunks(open_file, chunk_size)
d = async_reduce(update_hash, hashlib.sha256(), "")
d.addErrback(lambda err: err.trap(EOFError))
d.addCallback(lambda hasher: hasher.hexdigest())
return d
한다.
물론이 기능을 다시 작성하여 inlineCallbacks
을 피할 수있는 많은 다른 방법이 있습니다. 내가 선택한 방법으로 생성기 함수를 사용하지 않아도되므로 실제로는 도움이되지 못했습니다. 만약 그렇다면, 아마도 여러분이 제가 여기서 한 것처럼 문제를 분해 할 수 있습니다. 그 중 어떤 것도 발전기를 포함하지 않습니다.
리팩터링 또는 코드 검토를 위해 여기를 클릭하십시오. https://codereview.stackexchange.com/ – Joe