使用Python做大型計(jì)算任務(wù)時(shí),并且用mongodb做數(shù)據(jù)儲(chǔ)存時(shí),常常面臨大量讀寫數(shù)據(jù)庫的情況。尤其是大量更新任務(wù),由于不能批量操作,使用pymongo同步操作的話,相當(dāng)耗時(shí)。
使用多線程、多進(jìn)程確實(shí)有效,但編寫麻煩、消耗系統(tǒng)資源大(pymongo還不允許fork線程中共用連接)。這里主要瓶頸在于IO,使用單線程異步操作就會(huì)效果很好。
Motor是一個(gè)異步mongodb driver,支持異步讀寫mongodb。它通常用在基于Tornado的異步web服務(wù)器中。
Motor同時(shí)支持使用asyncio(Python3.4以上標(biāo)準(zhǔn)庫)作為異步模型,使用起來十分方便。
下面是一個(gè)對(duì)比例子。從某個(gè)mongodb集合中,遍歷讀取所有數(shù)據(jù),并update回去。update速度是主要瓶頸。
這里我們事先定義好,數(shù)據(jù)庫位于127.0.0.1:27017,數(shù)據(jù)庫名為testdb,集合名為test。我們處理其中title和content兩個(gè)較大的字段。
host = '127.0.0.1'
port = 27017
database = 'testdb'
下面是使用pymongo同步處理的例子:
from pymongo import MongoClient
connection = MongoClient(
host,
port
)
db = connection[database]
for doc in db.post.find({}, ['item_id', 'title', 'content']):
db.post.update({'item_id': doc.get('item_id')}, {
'$set': {
'title': doc.get('title'),
'content': doc.get('title')
}
})
以下是使用了asyncio和motor的例子:
import asyncio
from motor.motor_asyncio import AsyncIOMotorClient
connection = AsyncIOMotorClient(
host,
port
)
db = connection[database]
async def run():
async for doc in db.post.find({}, ['item_id', 'title', 'content']):
db.post.update({'item_id': doc.get('item_id')}, {
'$set': {
'title': doc.get('title'),
'content': doc.get('content'),
}
})
asyncio.get_event_loop().run_until_complete(run())
這里測試異步讀寫速度是同步的200倍左右(實(shí)際情況受IO時(shí)間影響,不一定是這個(gè)比例)。
可見,使用motor+asyncio做快速mongodb讀寫,方便有效。