麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 數據庫 > MongoDB > 正文

MongoDB游標超時的情況怎樣解決?

2024-09-07 00:22:29
字體:
來源:轉載
供稿:網友
      本文主要給大家分享關于MongoDB游標超時問題的解決辦法,小編認為是比較實用的,有這方面學習需要的朋友可以看看,希望大家閱讀完這篇文章之后大有收獲。
 
       當我們使用Python從MongoDB里面讀取數據時,可能會這樣寫代碼:
import pymongo
 
handler = pymongo.MongoClient().db.col
 
for row in handler.find():
 parse_data(row)
       短短4行代碼,讀取MongoDB里面的每一行數據,然后傳入parse_data做處理。處理完成以后再讀取下一行。邏輯清晰而簡單,能有什么問題?只要parse_data(row)不報錯,這一段代碼就完美無缺。但事實并非這樣。
 
       你的代碼可能會在for row in handler.find()這一行報錯。它的原因,說來話長。要解釋這個問題,我們首先就需要知道,handler.find()返回的并不是數據庫里面的數據,而是一個游標(cursor)對象。
 
       只有當你使用for循環開始迭代它的時候,游標才會真正去數據庫里面讀取數據。但是,如果每一次循環都連接數據庫,那么網絡連接會浪費大量時間。
 
       所以pymongo會一次性獲取100行,for row in handler.find()循環第一次的時候,它會連上MongoDB,讀取一百條數據,緩存到內存中。于是第2-100次循環,數據都是直接從內存里面獲取,不會再連接數據庫。
       當循環進行到底101次的時候,再一次連接數據庫,再讀取第101-200行內容……,這個邏輯非常有效地降低了網絡I/O耗時。但是,MongoDB默認游標的超時時間是10分鐘。10分鐘之內,必需再次連接MongoDB讀取內容刷新游標時間,否則,就會導致游標超時報錯:
 
pymongo.errors.CursorNotFound: cursor id 211526444773 not found
 
       所以,回到最開始的代碼中來,如果parse_data每次執行的時間超過6秒鐘,那么它執行100次的時間就會超過10分鐘。此時,當程序想讀取第101行數據的時候,程序就會報錯。
       為了解決這個問題,我們有4種辦法:
 
修改MongoDB的配置,延長游標超時時間,并重啟MongoDB。由于生產環境的MongoDB不能隨便重啟,所以這個方案雖然有用,但是排除。
一次性把數據全部讀取下來,再做處理:
all_data = [row for row in handler.find()]
 
for row in all_data:
 parse(row)
       這種方案的弊端也很明顯,如果數據量非常大,你不一定能全部放到內存里面。即使能夠全部放到內存中,但是列表推導式遍歷了所有數據,緊接著for循環又遍歷一次,浪費時間。
 
  3.讓游標每次返回的數據小于100條,這樣消費完這一批數據的時間就會小于10分鐘:
 
# 每次連接數據庫,只返回50行數據
for row in handler.find().batch_size(50):
 parse_data(row)
       但這種方案會增加數據庫的連接次數,從而增加I/O耗時。
 
  4.讓游標永不超時。通過設定參數no_cursor_timeout=True,讓游標永不超時:
 
cursor = handler.find(no_cursor_timeout=True)
for row in cursor:
 parse_data(row)
cursor.close() # 一定要手動關閉游標
       然而這個操作非常危險,因為如果你的Python程序因為某種原因意外停止了,這個游標就再也無法關閉了!除非重啟MongoDB,否則這些游標會一直留在MongoDB上,占用資源。
       當然可能有人會說,使用try...except把讀取數據的地方包住,只要拋出了異常,在處理異常的時候關閉游標即可:
cursor = handler.find(no_cursor_timeout=True)
try:
 for row in cursor:
 parse_data(row)
except Exception:
 parse_exception()
finally:
 cursor.close() # 一定要手動關閉游標
       其中finally里面的代碼,無論有沒有異常,都會執行。但這樣寫會讓代碼非常難看。為了解決這個問題,我們可以使用游標的上下文管理器:
 
with handler.find(no_cursor_timeout=True) as cursor:
 for row in cursor:
  parse_data(row)
       只要程序退出了with的縮進,游標自動就會關閉。如果程序中途報錯,游標也會關閉。它的原理可以用下面兩段代碼來解釋:
 
class Test:
 def __init__(self):
  self.x = 1
 
 def echo(self):
  print(self.x)
 
 def __enter__(self):
  print('進入上下文')
  return self
 
 def __exit__(self, *args):
  print('退出上下文')
  
with Test() as t:
 t.echo()
print('退出縮進')
       運行效果如下圖所示:
 
 
 
       接下來在with的縮進里面人為制造異常:
class Test:
 def __init__(self):
  self.x = 1
 
 def echo(self):
  print(self.x)
 
 def __enter__(self):
  print('進入上下文')
  return self
 
 def __exit__(self, *args):
  print('退出上下文')
  
with Test() as t:
 t.echo()
 1 + 'a' # 這里一定會報錯
print('退出縮進')
 
 
       無論在with的縮進里面發生了什么,Test這個類中的__exit__里面的代碼始終都會運行。我們來看看pymongo的游標對象里面,__exit__是怎么寫的,如下圖所示:
 
       可以看到,這里正是關閉游標的操作。因此,如果我們使用上下文管理器,就可以放心大膽地使用no_cursor_timeout=True參數了。

(編輯:武林網)

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 国产欧美日韩视频在线观看 | 中文字幕亚洲情99在线 | 毛片在线免费观看网址 | 欧美一级淫片免费播放口 | 国产免费一区二区三区 | 在线播放黄色网址 | a级高清免费毛片av在线 | 国产宾馆3p国语对白 | 亚洲成人精品久久久 | 在线播放亚洲视频 | 一级国产免费 | 激情网站免费观看 | 久久亚洲精品视频 | 嫩草www| 91精品国产综合久久婷婷香 | 黄色网址在线免费 | 亚洲最新色 | 久久99精品久久久久久秒播放器 | 国产在线区 | 亚洲天堂在线电影 | 成人男女免费视频 | 成人18免费观看 | 欧美成人一区二区视频 | 国产精品久久久久久模特 | 激情久久免费视频 | 操碰97 | 国产一级淫片免费看 | 国产精品一区二区三区在线 | 精品国产一区二区三区在线观看 | 日韩视频―中文字幕 | 青青草在线免费观看 | 国产乱乱视频 | 美国av片在线观看 | 失禁高潮抽搐喷水h | 99国产精品白浆在线观看免费 | xxxx18韩国护士hd老师 | 国产精品成年片在线观看, 激情小说另类 | 欧美一级电影网站 | 中国免费一级毛片 | 久久91亚洲人成电影网站 | 日日夜av |