2012-04-25 9 views
3

問題が発生しているかどうか、またはmongodbの利用可能なカーソル動作を理解できない場合は、誰かが私に理解を助けることができます。私はmongodb 2.0.4とpymongo 2.1.1を実行しています。pymongo tailableカーソルを空のコレクションで使用する

ここに問題を示すスクリプトがあります。

#!/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つのループの後に終了します。コレクションに最初のレコードを追加すると、テーリングカーソルが動作するように動作するようになります。

また、StopIteration例外を処理すると、cursor.next()がデータを待機していますか?バックエンドがデータが利用可能になるまでブロックできないのはなぜですか?私はawait_dataが実際に何かをすると仮定していましたが、接続を待たずに接続を2〜2秒以上待つだけのようです。

ほとんどの例では、cursor.aliveループの周りに2番目のWhileループを入れていますが、スクリプトが空のコレクションの末尾に来ると、ループはスピンしてCPU時間を無駄にするだけです。私は実際にアプリケーションの起動時にこの問題を避けるために単一の偽のレコードを入れたくないのです。

+0

何かを無限にブロックすることは決して良い考えではありません – mensi

+0

gobject.MainLoop()。run();)に伝えてください – DaGoodBoy

答えて

1

これは既知の動作であり、2つのループ "解決策"がこのケースを回避するために受け入れられている方法です。コレクションが空の場合は、直ちにリトライしてタイトなループに入るのではなく、短時間スリープ状態にすることができます(特にデータがすぐにテールになることが予想される場合)。

+3

うん、それは吸う。私はそれをしましたが、それは私に汚れを感じさせました。 – DaGoodBoy

関連する問題