2013-02-21 1 views
5

엔티티를 업데이트하고 데이터 저장소에 저장 한 다음 요청을 처리하기 전에 (백그라운드 작업을 대기열에 넣고 일부 결과를 json-serialize하는 등) 몇 가지 추가 작업을 수행해야하는 요청 처리기가 있습니다. 엔티티가 저장되는 동안 추가 작업이 완료되도록이 코드를 병렬 처리하려고합니다.ndb가 put_async() 호출을 일괄 처리하지 못하게하고 RPC가 즉시 실행되게하는 방법?

class FooHandler(webapp2.RequestHandler): 
    @ndb.toplevel 
    def post(self): 
     foo = yield Foo.get_by_id_async(some_id) 

     # Do some work with foo 

     # Don't yield, as I want to perform the code that follows 
     # while foo is being saved to the datastore. 
     # I'm in a toplevel, so the handler will not exit as long as 
     # this async request is not finished. 
     foo.put_async() 

     taskqueue.add(...) 
     json_result = generate_result() 
     self.response.headers["Content-Type"] = "application/json; charset=UTF-8" 
     self.response.write(json_result) 

그러나, Appstats는 datastore.Put RPC는 taskqueue.Add 후, 순차적으로 수행되고 있음을 보여줍니다 :

Appstats screenshot

약간은 주위 파고

여기 내 처리기 코드는 아래로 비등 무엇 ndb.context.pyput_async() 호출이 RPC가 즉시 발행되는 대신 AutoBatcher에 추가되는 것을 보여줍니다.

따라서 toplevel이 완료되면 비동기 호출이 완료 될 때까지 이 플러시되는 것으로 추정됩니다.

일괄 처리 puts는 특정 시나리오에서 실질적인 이점을 가지고 있음을 이해합니다. 그러나 제 경우에는 put RPC를 즉시 보내 줘서 엔티티가 저장되는 동안 다른 작업을 수행 할 수 있습니다.

내가 yield foo.put_async() 할 경우, 나는 Appstats에서 같은 폭포를 얻을 수 있지만, datastore.Put에 가장 우선적으로 수행되고 : yield 내 핸들러가 기다릴 수로,

2nd Appstats screenshot

이 예상 될 수있다 나머지 코드를 실행하기 전에 put_async() 호출을 완료하십시오.

나는 마우스 오른쪽 foo.put_async()ndb.get_context().flush()에 대한 호출을 추가 시도하지만, datastore.Puttaskqueue.BulkAdd 전화는 여전히 Appstats에 따라 병렬로 만든되지 않습니다.

내 질문은 : put_async()에 대한 호출을 자동 배터를 우회하여 RPC를 즉시 발급 할 수 있습니까?

foo = yield Foo.get_by_id_async(some_id) 
future = foo.put_async() 
future.done() 

NDB 요청은 autobatcher에 넣어 얻을, 당신은 결과를 필요로 할 때 배치가 RPC로 전송됩니다 :

+0

생산 중이거나 현지에 있습니까? – Lipis

+0

제작 중입니다. –

답변

6

그것을 할 지원되는 방법은 없습니다. 어쩌면 있어야합니다. 이게 작동하면해볼 수 있니?기본적으로는 RPC를 기다리고 제외() 수행 run0 무엇의 대부분을 시도하려는 -

loop - ndb.eventloop.get_event_loop() 
while loop.run_idle(): 
    pass 

당신은 당신이 시도 할 수있는 다른 무엇을 볼 수 NDB/eventloop.py의 소스 코드를 볼 수 있습니다. 특히,이 작업을 수행해야한다는 것을 가능 :

while loop.current: 
    loop.run0() 
while loop.run_idle(): 
    pass 

(당신도 처리 할 수있는 다른 조건이 있기 때문에 여전히 지원되지 않지만 그이 발생하지 않는 것 당신의 예)

+0

'foo.put_async()'를 호출 한 직후 제안한 2 개의 루프가 뒤 따르는'ndb.get_context(). flush()'를 호출하여 작동하게했습니다. 내 사용 시나리오가 드문 경우가 아니라는 점에서 공식적으로 지원되는 방법이 있어야한다고 생각합니다. 엔티티를 저장하는 동안 엔터티를 저장 한 다음 나머지 처리기 작업을 처리하는 방식으로 생각하지 않습니다. 나는 그것에 대한 기능 요청을 제출 : http://code.google.com/p/googleappengine/issues/detail?id=8863 –

+0

내가 정말로 필요하다고 생각 taskqueue.add_async 유휴/대기열로 작업 큐 rpc를 얻을 수 있습니다. 이벤트 루프에서 rpc 루프. http://code.google.com/p/appengine-ndb-experiment/issues/detail?id=180 – tesdal

+0

정확히 어떤 코드가 효과가 있었습니까? flush()는 tasklet이므로 결과를 산출해야하므로 지연 시간이 길어질 수 있습니다. 어쨌든, 이것은 유용한 기능이 될 것이라고 동의했습니다. 아마도 NDB 추적기에 파일을 저장하면 더 많은 관심을 갖게 될 것입니다. –

-2

는 나는 그것이 도움이 될 것입니다 100 % 확실하지 않다,이보십시오. foo.put_async()의 결과를 필요로하지 않기 때문에, 다른 ndb 호출을 할 때까지 또는 @ ndb.toplevel이 끝날 때까지 전송되지 않습니다.

future.done() 호출을 차단하지는 않지만 요청을 트리거 할 수 있다고 생각합니다.

또 다른 것은

는 작업이 강제로 시도 :

ndb.get_context().flush() 
+0

감사합니다.하지만 아무 것도하지 않습니다. 'Future.done()'는 아무 처리도하지 않고'return self._done' 만하고'Context.flush()'를 이미 시도했습니다. –

관련 문제