Pymongo 3.0.2 比 2.8.1 慢
Pymongo 3.0.2 slower than 2.8.1
我正在 运行在 MongoDB 上安装一个简单的 Django 应用程序,并且最近升级到 PyMongo 3.0.2 —— 但是这个 运行 速度非常慢。如果我降级到 PyMongo 2.8.1 或 2.7.2,它会再次加速。 MongoDB 3 和 2.6 都会发生这种情况,所以我认为一些基本的东西已经改变了。根据变更日志,PyMongo 3 实际上应该加快很多,而且我找不到任何会导致性能下降的明显变化。我在 SO 或 Google 上没有发现相关问题。这是 Django 1.6.4 和 Python 2.7.5.
很难举出一个这样的代码示例,但我们使用的是单个 MongoDB 实例(没有分片,没有远程主机),并且在我们的每个方法中都使用了 mongo_client
,我们在方法的末尾调用close()
。如果我们不断关闭连接,是否有一些新的连接重新打开行为可能会降低客户端的速度?示例方法如下:
from pymongo import MongoClient
mongo_client = MongoClient()
collection = mongo_client[self._db_prefix + 'assessment']['Assessment']
if collection.find({'itemIds': str(item_id)}).count() != 0:
raise errors.IllegalState('this Item is being used in one or more Assessments')
collection = mongo_client[self._db_prefix + 'assessment']['Item']
item_map = collection.find_one({'_id': ObjectId(item_id.get_identifier())})
if item_map is None:
raise errors.NotFound()
objects.Item(item_map, db_prefix=self._db_prefix, runtime=self._runtime)._delete()
delete_result = collection.delete_one({'_id': ObjectId(item_id.get_identifier())})
if delete_result.deleted_count == 0:
raise errors.NotFound()
mongo_client.close()
更新 1:
按照建议,我使用 timeit
库创建了一个专用负载测试。使用 PyMongo 3.0.2:
timeit.timeit('MongoClient()["test_blah"]["blah"].insert_one({"foo":"bar"})', number=10000, setup="from pymongo import MongoClient")
实际抛出错误:
File "~/Documents/virtual_environments/assessments/lib/python2.7/site-packages/pymongo/pool.py", line 58, in _raise_connection_failure
raise AutoReconnect(msg)
AutoReconnect: localhost:27017: [Errno 49] Can't assign requested address
然后我降级到 PyMongo 2.8.1:
pip install pymongo==2.8.1
和运行相同的命令在python shell:
timeit.timeit('MongoClient()["test_blah"]["blah"].insert({"foo":"bar"})', number=10000, setup="from pymongo import MongoClient")
8.372910976409912
这次它真的完成了...所以看起来新的 insert_one
方法做了一些不同的事情,它没有关闭连接?
更新2(含解决方案):
Bernie 的回答以及这个 SO question 帮助我们指明了正确的方向。除了使用单个 MongoClient()
,我们的问题是我们在每个方法结束时关闭连接。下面的示例 timeit
s(均为 PyMongo 3.0.2):
>>> timeit.timeit('client["test_blah"]["blah"].insert_one({"foo":"bar"}); client.close()', number=10, setup="from pymongo import MongoClient; client=MongoClient()")
4.520946025848389
>>> timeit.timeit('client["test_blah"]["blah"].insert_one({"foo":"bar"})', number=10, setup="from pymongo import MongoClient; client=MongoClient()")
0.004940986633300781
手动关闭客户端是性能杀手...慢 1000 倍。可能是 Bernie 提到的监控线程关闭缓慢造成的?
我认为您遇到的问题是由于 MongoClient 产生了一个后台监控线程。这是 PyMongo 3.0 中的新功能,与 PyMongo 2.x 中 MongoReplicaSetClient 的行为相匹配。您应该能够通过仅生成一个 MongoClient 实例(这是使用 MongoClient 的首选方式)来加快速度。
>>> import timeit
>>> timeit.timeit('client["test_blah"]["blah"].insert_one({"foo":"bar"})', number=10000, setup="from pymongo import MongoClient; client = MongoClient()")
2.2610740661621094
>>> import pymongo
>>> pymongo.version
'3.0.2'
>>> timeit.timeit('client["test_blah"]["blah"].insert({"foo":"bar"})', number=10000, setup="from pymongo import MongoClient; client = MongoClient()")
2.3010458946228027
>>> import pymongo
>>> pymongo.version
'2.8.1'
我还认为监控线程关闭的时间太长,我会研究解决该问题的方法。
我正在 运行在 MongoDB 上安装一个简单的 Django 应用程序,并且最近升级到 PyMongo 3.0.2 —— 但是这个 运行 速度非常慢。如果我降级到 PyMongo 2.8.1 或 2.7.2,它会再次加速。 MongoDB 3 和 2.6 都会发生这种情况,所以我认为一些基本的东西已经改变了。根据变更日志,PyMongo 3 实际上应该加快很多,而且我找不到任何会导致性能下降的明显变化。我在 SO 或 Google 上没有发现相关问题。这是 Django 1.6.4 和 Python 2.7.5.
很难举出一个这样的代码示例,但我们使用的是单个 MongoDB 实例(没有分片,没有远程主机),并且在我们的每个方法中都使用了 mongo_client
,我们在方法的末尾调用close()
。如果我们不断关闭连接,是否有一些新的连接重新打开行为可能会降低客户端的速度?示例方法如下:
from pymongo import MongoClient
mongo_client = MongoClient()
collection = mongo_client[self._db_prefix + 'assessment']['Assessment']
if collection.find({'itemIds': str(item_id)}).count() != 0:
raise errors.IllegalState('this Item is being used in one or more Assessments')
collection = mongo_client[self._db_prefix + 'assessment']['Item']
item_map = collection.find_one({'_id': ObjectId(item_id.get_identifier())})
if item_map is None:
raise errors.NotFound()
objects.Item(item_map, db_prefix=self._db_prefix, runtime=self._runtime)._delete()
delete_result = collection.delete_one({'_id': ObjectId(item_id.get_identifier())})
if delete_result.deleted_count == 0:
raise errors.NotFound()
mongo_client.close()
更新 1:
按照建议,我使用 timeit
库创建了一个专用负载测试。使用 PyMongo 3.0.2:
timeit.timeit('MongoClient()["test_blah"]["blah"].insert_one({"foo":"bar"})', number=10000, setup="from pymongo import MongoClient")
实际抛出错误:
File "~/Documents/virtual_environments/assessments/lib/python2.7/site-packages/pymongo/pool.py", line 58, in _raise_connection_failure
raise AutoReconnect(msg)
AutoReconnect: localhost:27017: [Errno 49] Can't assign requested address
然后我降级到 PyMongo 2.8.1:
pip install pymongo==2.8.1
和运行相同的命令在python shell:
timeit.timeit('MongoClient()["test_blah"]["blah"].insert({"foo":"bar"})', number=10000, setup="from pymongo import MongoClient")
8.372910976409912
这次它真的完成了...所以看起来新的 insert_one
方法做了一些不同的事情,它没有关闭连接?
更新2(含解决方案):
Bernie 的回答以及这个 SO question 帮助我们指明了正确的方向。除了使用单个 MongoClient()
,我们的问题是我们在每个方法结束时关闭连接。下面的示例 timeit
s(均为 PyMongo 3.0.2):
>>> timeit.timeit('client["test_blah"]["blah"].insert_one({"foo":"bar"}); client.close()', number=10, setup="from pymongo import MongoClient; client=MongoClient()")
4.520946025848389
>>> timeit.timeit('client["test_blah"]["blah"].insert_one({"foo":"bar"})', number=10, setup="from pymongo import MongoClient; client=MongoClient()")
0.004940986633300781
手动关闭客户端是性能杀手...慢 1000 倍。可能是 Bernie 提到的监控线程关闭缓慢造成的?
我认为您遇到的问题是由于 MongoClient 产生了一个后台监控线程。这是 PyMongo 3.0 中的新功能,与 PyMongo 2.x 中 MongoReplicaSetClient 的行为相匹配。您应该能够通过仅生成一个 MongoClient 实例(这是使用 MongoClient 的首选方式)来加快速度。
>>> import timeit
>>> timeit.timeit('client["test_blah"]["blah"].insert_one({"foo":"bar"})', number=10000, setup="from pymongo import MongoClient; client = MongoClient()")
2.2610740661621094
>>> import pymongo
>>> pymongo.version
'3.0.2'
>>> timeit.timeit('client["test_blah"]["blah"].insert({"foo":"bar"})', number=10000, setup="from pymongo import MongoClient; client = MongoClient()")
2.3010458946228027
>>> import pymongo
>>> pymongo.version
'2.8.1'
我还认为监控线程关闭的时间太长,我会研究解决该问题的方法。