背景
先说一下标题,当我不知道问题的具体原因的时候,上面的标题就是我在搜索引擎中输入的内容。同样的,我还尝试过以下几种搜索组合:
Pymongo insert hangs
Pymongo insert stop
Pymongo insert no return
MongoDB insert hangs
MongoDB insert stop
MongoDB insert no return
从上面几个搜索的关键词,大家也能看出来问题的基本背景,就是使用 Pymongo 执行 insert,但是卡住了。
所说的卡住了,就是说,没有返回值,没有异常,没有报错,就是程序走到那里就不继续向下执行了。
问题描述
以下是代码的基本结构:
clt = MongoClient("mongodb://192.168.x.x:27017")
db = clt['test_bottle']
col = dest_db['test_result']
idx = 0
rs = []
for r in records:
rs.append(r)
idx += 1
if idx % 100 == 0:
col.insert_many(rs)
rs = []
可以看到,很简单,很基础的代码,就是循环插入。问题的现象就是,代码执行到 col.insert_many(rs)
的时候,偶尔会出现程序卡住的情况。
这个卡住是随机的,有时候执行几次就卡住,有时候数据跑完一圈(几百万条数据)也没卡住。
奇怪吧。
这个问题比较诡异的就是,为什么会卡住,如果有问题,你报错就可以了,我捕获异常,然后特殊处理就可以,但是为什么会卡住。
问题分析
行了,直接说问题原因吧:
没有设置超时时间。
可能有的人会很奇怪,这个东西跟超时时间有什么关系?
我们来看一下 MongoDB 的官方文档:
可以看到,关于超时时间的设定一共有两个,分别是 connectTimeoutMS
和 socketTimeoutMS
,有点类似之前说过的 requests
模块的 connect timeout
和 read timeout
,即:连接超时时间
、读取超时时间
。
这里比较坑的问题就出现了,这两个配置的默认值是 不超时(never to timeout)
。
所以,当我们没有执行这两个配置的时候,程序就会一直等待连接或者等待读取数据,也就是咱们上面所说的「卡住」。
解决方法
既然知道了问题原因,那解决思路就清晰了,设置一下超时时间即可。
设置的方式也有很多种,比如我这里就是直接修改了 MongoDB 的连接 uri:
也就是把上面的
clt = MongoClient("mongodb://192.168.x.x:27017")
修改为
clt = MongoClient("mongodb://192.168.x.x:27017/?socketTimeoutMS=3000&connectTimeoutMS=3000")
我这里设置的超时时间都是 3000(3s)
,大家可以根据自身情况自行设置。
当然,如果这样设置完了之后,记得捕获异常,然后做特殊处理。
好了,今天就和大家分享到这里,祝大家变得更强。
补充知识点:
卡住的「卡」音 qiǎ
,不是 kǎ
。