3

DBエンティティを反復処理し、タスクで実行するコードがいくつかあります-以下を参照してください。

アプリエンジンでExceeded soft private memory limitエラーが発生しました。実際にチェックmemory_usage().current()すると問題が確認されます。ロギング ステートメントからの出力については、以下を参照してください。foos のバッチがフェッチされるたびに、メモリが増加するようです。

私の質問は、メモリがガベージ コレクションされないのはなぜですか? whileループ (それぞれループとループ) の反復ごとに、名前とforを再利用すると、とが指していたオブジェクトが「参照解除」される (つまり、そのため、ガベージ コレクションの対象となり、メモリが不足するとガベージ コレクションの対象になります。しかし、明らかにそれは起こっていません。foosfoofoosfoo

from google.appengine.api.runtime import memory_usage

batch_size = 10
dict_of_results = {}
results = 0
cursor = None

while True:
  foos = models.Foo.all().filter('status =', 6)
  if cursor:
     foos.with_cursor(cursor)

  for foo in foos.run(batch_size = batch_size):

     logging.debug('on result #{} used memory of {}'.format(results, memory_usage().current()))
     results +=1

     bar  = some_module.get_bar(foo)

     if bar:
        try:
           dict_of_results[bar.baz] += 1
        except KeyError:
           dict_of_results[bar.baz] = 1


     if results >= batch_size:
        cursor = foos.cursor()
        break

  else:
     break   

そして some_module.py で

def get_bar(foo):

  for bar in foo.bars:
    if bar.status == 10:
       return bar

  return None  

logging.debug の出力 (短縮)

on result #1 used memory of 43
on result #2 used memory of 43
.....
on result #20 used memory of 43
on result #21 used memory of 49
.....
on result #32 used memory of 49
on result #33 used memory of 54
.....
on result #44 used memory of 54
on result #45 used memory of 59
.....
on result #55 used memory of 59
.....
.....
.....

on result #597 used memory of 284.3
Exceeded soft private memory limit of 256 MB with 313 MB after servicing 1 requests total
4

2 に答える 2

3

バッチ ソリューションが db のバッチ処理と競合しているようで、多くの余分なバッチがぶら下がっています。

を実行するquery.run(batch_size=batch_size)と、db は制限全体が完了するまでクエリを実行します。バッチの最後に到達すると、db は次のバッチを取得します。ただし、db がこれを行った直後に、ループを終了して再度開始します。これが意味することは、バッチ 1 -> n がすべてメモリ内に 2 回存在することです。最後のクエリ フェッチで 1 回、次のクエリ フェッチで 1 回。

すべてのエンティティをループしたい場合は、db にバッチ処理を任せてください:

foos = models.Foo.all().filter('status =', 6)
for foo in foos.run(batch_size = batch_size):
  results +=1
  bar  = some_module.get_bar(foo)
  if bar:
    try:
      dict_of_results[bar.baz] += 1
    except KeyError:
      dict_of_results[bar.baz] = 1

または、バッチ処理を自分で処理したい場合は、db がバッチ処理を行わないことを確認してください。

while True:
  foo_query = models.Foo.all().filter('status =', 6)
  if cursor:
    foo_query.with_cursor(cursor)
  foos = foo_query.fetch(limit=batch_size)
  if not foos:
    break

  cursor = foos.cursor()
于 2015-10-01T17:43:43.203 に答える