2012-01-17 2 views
3

실험용 BLOBSTORE 파일 API를 사용하여 일부 이벤트 데이터가 포함 된 CSV 파일을 작성하고 있습니다. 많은 데이터가 있으므로 쓰기를 일괄 처리합니다. 내 코드는 백엔드에서 실행되므로 시간이 많이 걸리지 만 메모리가 부족하여 그 이유를 이해할 수 없습니다. 프로세스가 메모리 140 메가 바이트까지 사용하는 데 중단합니다 약 20 시간 전에큰 파일을 BLOB 저장소에 저장하고 메모리가 부족한 경우

from __future__ import with_statement 
from google.appengine.api import files 

q = Event.all() 

events = q.fetch(50) 
while events: 
    with files.open(blobname, 'a') as f: 
     buf = StringIO() 

     for event in events: 
      buf.write(event.id) 
      buf.write(',') 
      buf.write(`event.logged`) 
      buf.write(',') 
      buf.write(event.type) 
      buf.write(',') 
      buf.write(event.timestamp) 
      buf.write(',') 

      needAmpersand = False 
      for prop in event.dynamic_properties(): 
       if needAmpersand: 
        buf.write('&') 
       needAmpersand = True 
       buf.write(prop + '=' + str(getattr(event, prop))) 
      buf.write('\n') 

     f.write(buf.getvalue()) 
     buf.close() 

    events = q.fetch(50) 

files.finalize(blobname) 

이 코드는 동안 이벤트 루프의 둘레를 만드는 :

여기에 코드입니다. 이벤트는이 응용 프로그램과 관련된 데이터베이스 모델입니다. 이벤트는 기본적으로 원격 컴퓨터에서 일어나는 일의 기록입니다. 나중에 이러한 이벤트는 통계를 작성하기 위해지도 축소 작업에 의해 처리됩니다. 이제는 해당 이벤트를 다운로드하기 만하면됩니다. 우리 데이터베이스에는 1000 가지의 이벤트가 100 가지가 있습니다 (나중에 다른 방식으로 저장하는 것으로 전환하지만 지금은이 방식입니다). f.close()이 각각 f.__exit__()

단지 f.write (..)라는이 코드의 이전 인스턴스에 의해 호출 될 때

나는, f.open와 그것이 절과를 완료 할 때마다 호출 할 f.close 원인이 있습니다 엘리먼트는 'StringIO'에 쓰여진다. 이 이전 버전의 메모리는 훨씬 더 빠르게 실행되었지만 그렇지 않은 경우 비슷한 방식으로 작동합니다. 메모리를 누출시키는 원인이되는이 코드에 대해서는 여전히 무언가가 있습니다.

도움 말?

난 그냥 f.write을 (buf.getvalue()) 주석 시도하고 그것은 분명히 아무것도 가진 Blob 저장소 항목을 만들지 않습니다 있지만, 그것은 결국 완전한 처리 한 않습니다 업데이트 모든 이벤트 엔티티. 뭔가 빠졌거나 f.write() 메모리 누수 또는 finalize() 때까지 모든 버퍼가?

+1

'이벤트'란 무엇입니까? AppEngine 객체? –

+0

"원본 버전"은 무엇을합니까? 그것이 무엇을했는지 모른 채 '더 빨리 깨달았다'는 것을 아는 것은 도움이되지 않습니다. –

+0

감사합니다. 더 명확한 정보를 제공하도록 질문을 수정했습니다. – Jules

답변

1

f.write(buf.getvalue())으로 전화 할 때 StringIO에게 하나의 메모리 개체로 전환하여 전달하도록 요청할 것입니다. 그건 비싸 질거야.

buf.seek(0)을 시도하면 스트림의 처음으로 되감기하고 f.write(buf)을 전달합니다. StringIO은 파일과 유사한 객체이며 f.write은 스트림을 통해 읽을 수 있어야합니다.

source을 확인하십시오. file_service_pb.AppendRequest이 StringIO를 처리 할 수 ​​있는지 여부는 문서 또는 코드에서 분명하지 않습니다. 시도 해봐.

+0

유용한 관찰, 나는 그걸 가지고 놀거야. 그러나'buf.getvalue()'는 문자열의 임시 복사본을 만들어야 할 수도 있습니다. 이는 비효율적이라고 동의하지만 누설해서는 안됩니다. 메모리가 부족하기 전에 루프를 20 번 반복합니다. 전환 한 경우 최고 메모리가 낮기 때문에 시간이 더 걸릴 수 있지만 전반적인 문제는 해결되지 않습니다. – Jules

+0

실제로. "파일"은 자체 버퍼를 저장할 수도 있습니다. 현재 점검 할 위치는 아니지만 GAE 파일 객체에서'flush' 메소드를 찾으십시오. – Joe

관련 문제