3

問題が発生した場合、またはmongodbのtailableカーソルの動作を理解していない場合は、誰かが理解してくれることを願っています。私はmongodb 2.0.4とpymongo 2.1.1を実行しています。

問題を示すスクリプトを次に示します。

#!/usr/bin/python

import sys
import time
import pymongo

MONGO_SERVER = "127.0.0.1"
MONGO_DATABASE = "mdatabase"
MONGO_COLLECTION = "mcollection"

mongodb    = pymongo.Connection(MONGO_SERVER, 27017)
database   = mongodb[MONGO_DATABASE]

if MONGO_COLLECTION in database.collection_names():
  database[MONGO_COLLECTION].drop()

print "creating capped collection"
database.create_collection(
  MONGO_COLLECTION,
  size=100000,
  max=100,
  capped=True
)
collection = database[MONGO_COLLECTION]

# Run this script with any parameter to add one record
# to the empty collection and see the code below
# loop correctly
#
if len(sys.argv[1:]):
  collection.insert(
    {
      "key" : "value",
    }
  )

# Get a tailable cursor for our looping fun
cursor = collection.find( {},
                          await_data=True,
                          tailable=True )

# This will catch ctrl-c and the error thrown if
# the collection is deleted while this script is
# running.
try:

  # The cursor should remain alive, but if there
  # is nothing in the collection, it dies after the
  # first loop. Adding a single record will
  # keep the cursor alive forever as I expected.
  while cursor.alive:
    print "Top of the loop"
    try:
      message = cursor.next()
      print message
    except StopIteration:
      print "MongoDB, why you no block on read?!"
      time.sleep(1)

except pymongo.errors.OperationFailure:
  print "Delete the collection while running to see this."

except KeyboardInterrupt:
  print "trl-C Ya!"
  sys.exit(0)

print "and we're out"

# End

したがって、コードを見ると、私が抱えている問題を示すのは非常に簡単です。空のコレクション (適切にキャップされ、テーリングの準備ができている) に対してコードを実行すると、カーソルが停止し、コードは 1 回ループした後に終了します。コレクションに最初のレコードを追加すると、テーリング カーソルの動作が期待どおりに動作します。

また、データを待っているcursor.next()を殺すStopIteration例外との取引は何ですか? データが利用可能になるまでバックエンドがブロックできないのはなぜですか? 私は await_data が実際に何かをするだろうと思っていましたが、それがない場合よりも 1 秒か 2 秒長く接続を待機させているだけのようです。

ネット上のほとんどの例では、cursor.alive ループの周りに 2 番目の While True ループを配置していますが、スクリプトが空のコレクションを追跡すると、ループはスピンしてスピンし、CPU 時間を無駄に浪費します。アプリケーションの起動時にこの問題を回避するためだけに、単一の偽のレコードを入れたくありません。

4

1 に答える 1

1

これは既知の動作であり、2つのループの「解決策」がこのケースを回避するための一般的な方法です。コレクションが空の場合、提案したようにすぐに再試行してタイトループに入るのではなく、短時間スリープすることができます(特に、すぐにデータがテールになると予想される場合)。

于 2012-04-25T19:54:11.520 に答える