1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時(shí)間:8:30-17:00
      你可能遇到了下面的問題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      如何解決MongoDB游標(biāo)超時(shí)問題-創(chuàng)新互聯(lián)

      這篇文章給大家分享的是有關(guān)如何解決MongoDB游標(biāo)超時(shí)問題的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。

      創(chuàng)新互聯(lián)-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比長沙縣網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式長沙縣網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋長沙縣地區(qū)。費(fèi)用合理售后完善,十載實(shí)體公司更值得信賴。

      當(dāng)我們使用Python從MongoDB里面讀取數(shù)據(jù)時(shí),可能會(huì)這樣寫代碼:

      import pymongo
      
      handler = pymongo.MongoClient().db.col
      
      for row in handler.find():
       parse_data(row)

      短短4行代碼,讀取MongoDB里面的每一行數(shù)據(jù),然后傳入parse_data做處理。處理完成以后再讀取下一行。邏輯清晰而簡單,能有什么問題?只要parse_data(row)不報(bào)錯(cuò),這一段代碼就完美無缺。

      但事實(shí)并非這樣。

      你的代碼可能會(huì)在for row in handler.find()這一行報(bào)錯(cuò)。它的原因,說來話長。

      要解釋這個(gè)問題,我們首先就需要知道,handler.find()返回的并不是數(shù)據(jù)庫里面的數(shù)據(jù),而是一個(gè)游標(biāo)(cursor)對(duì)象。如下圖所示:

      如何解決MongoDB游標(biāo)超時(shí)問題

      只有當(dāng)你使用for循環(huán)開始迭代它的時(shí)候,游標(biāo)才會(huì)真正去數(shù)據(jù)庫里面讀取數(shù)據(jù)。

      但是,如果每一次循環(huán)都連接數(shù)據(jù)庫,那么網(wǎng)絡(luò)連接會(huì)浪費(fèi)大量時(shí)間。

      所以pymongo會(huì)一次性獲取100行,for row in handler.find()循環(huán)第一次的時(shí)候,它會(huì)連上MongoDB,讀取一百條數(shù)據(jù),緩存到內(nèi)存中。于是第2-100次循環(huán),數(shù)據(jù)都是直接從內(nèi)存里面獲取,不會(huì)再連接數(shù)據(jù)庫。

      當(dāng)循環(huán)進(jìn)行到底101次的時(shí)候,再一次連接數(shù)據(jù)庫,再讀取第101-200行內(nèi)容……

      這個(gè)邏輯非常有效地降低了網(wǎng)絡(luò)I/O耗時(shí)。

      但是,MongoDB默認(rèn)游標(biāo)的超時(shí)時(shí)間是10分鐘。10分鐘之內(nèi),必需再次連接MongoDB讀取內(nèi)容刷新游標(biāo)時(shí)間,否則,就會(huì)導(dǎo)

      致游標(biāo)超時(shí)報(bào)錯(cuò):

      pymongo.errors.CursorNotFound: cursor id 211526444773 not found

      如下圖所示:

      如何解決MongoDB游標(biāo)超時(shí)問題

      所以,回到最開始的代碼中來,如果parse_data每次執(zhí)行的時(shí)間超過6秒鐘,那么它執(zhí)行100次的時(shí)間就會(huì)超過10分鐘。此時(shí),當(dāng)程序想讀取第101行數(shù)據(jù)的時(shí)候,程序就會(huì)報(bào)錯(cuò)。

      為了解決這個(gè)問題,我們有4種辦法:

      1. 修改MongoDB的配置,延長游標(biāo)超時(shí)時(shí)間,并重啟MongoDB。由于生產(chǎn)環(huán)境的MongoDB不能隨便重啟,所以這個(gè)方案雖然有用,但是排除。

      2. 一次性把數(shù)據(jù)全部讀取下來,再做處理:

      all_data = [row for row in handler.find()]
      
      for row in all_data:
       parse(row)

      這種方案的弊端也很明顯,如果數(shù)據(jù)量非常大,你不一定能全部放到內(nèi)存里面。即使能夠全部放到內(nèi)存中,但是列表推導(dǎo)式遍歷了所有數(shù)據(jù),緊接著for循環(huán)又遍歷一次,浪費(fèi)時(shí)間。

        3.讓游標(biāo)每次返回的數(shù)據(jù)小于100條,這樣消費(fèi)完這一批數(shù)據(jù)的時(shí)間就會(huì)小于10分鐘:

      # 每次連接數(shù)據(jù)庫,只返回50行數(shù)據(jù)
      for row in handler.find().batch_size(50): 
       parse_data(row)

      但這種方案會(huì)增加數(shù)據(jù)庫的連接次數(shù),從而增加I/O耗時(shí)。

        4.讓游標(biāo)永不超時(shí)。通過設(shè)定參數(shù)no_cursor_timeout=True,讓游標(biāo)永不超時(shí):

      cursor = handler.find(no_cursor_timeout=True)
      for row in cursor:
       parse_data(row)
      cursor.close() # 一定要手動(dòng)關(guān)閉游標(biāo)

      然而這個(gè)操作非常危險(xiǎn),因?yàn)槿绻愕腜ython程序因?yàn)槟撤N原因意外停止了,這個(gè)游標(biāo)就再也無法關(guān)閉了!除非重啟MongoDB,否則這些游標(biāo)會(huì)一直留在MongoDB上,占用資源。

      當(dāng)然可能有人會(huì)說,使用try...except把讀取數(shù)據(jù)的地方包住,只要拋出了異常,在處理異常的時(shí)候關(guān)閉游標(biāo)即可:

      cursor = handler.find(no_cursor_timeout=True)
      try:
       for row in cursor:
       parse_data(row)
      except Exception:
       parse_exception()
      finally:
       cursor.close() # 一定要手動(dòng)關(guān)閉游標(biāo)

      其中finally里面的代碼,無論有沒有異常,都會(huì)執(zhí)行。

      但這樣寫會(huì)讓代碼非常難看。為了解決這個(gè)問題,我們可以使用游標(biāo)的上下文管理器:

      with handler.find(no_cursor_timeout=True) as cursor:
       for row in cursor:
        parse_data(row)

      只要程序退出了with的縮進(jìn),游標(biāo)自動(dòng)就會(huì)關(guān)閉。如果程序中途報(bào)錯(cuò),游標(biāo)也會(huì)關(guān)閉。

      它的原理可以用下面兩段代碼來解釋:

      class Test:
       def __init__(self):
        self.x = 1
      
       def echo(self):
        print(self.x)
      
       def __enter__(self):
        print('進(jìn)入上下文')
        return self
      
       def __exit__(self, *args):
        print('退出上下文')
        
      with Test() as t:
       t.echo()
      print('退出縮進(jìn)')

      運(yùn)行效果如下圖所示:

      如何解決MongoDB游標(biāo)超時(shí)問題

      接下來在with的縮進(jìn)里面人為制造異常:

      class Test:
       def __init__(self):
        self.x = 1
      
       def echo(self):
        print(self.x)
      
       def __enter__(self):
        print('進(jìn)入上下文')
        return self
      
       def __exit__(self, *args):
        print('退出上下文')
        
      with Test() as t:
       t.echo()
       1 + 'a' # 這里一定會(huì)報(bào)錯(cuò)
      print('退出縮進(jìn)')

      運(yùn)行效果如下圖所示:

      如何解決MongoDB游標(biāo)超時(shí)問題

      無論在with的縮進(jìn)里面發(fā)生了什么,Test這個(gè)類中的__exit__里面的代碼始終都會(huì)運(yùn)行。

      我們來看看pymongo的游標(biāo)對(duì)象里面,__exit__是怎么寫的,如下圖所示:

      如何解決MongoDB游標(biāo)超時(shí)問題

      可以看到,這里正是關(guān)閉游標(biāo)的操作。

      因此,如果我們使用上下文管理器,就可以放心大膽地使用no_cursor_timeout=True參數(shù)了。

      感謝各位的閱讀!關(guān)于“如何解決MongoDB游標(biāo)超時(shí)問題”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!


      分享文章:如何解決MongoDB游標(biāo)超時(shí)問題-創(chuàng)新互聯(lián)
      URL網(wǎng)址:http://ef60e0e.cn/article/cosspd.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        余姚市| 隆化县| 屯留县| 西畴县| 富裕县| 中方县| 泌阳县| 郓城县| 鹤岗市| 石家庄市| 阿拉尔市| 施甸县| 法库县| 襄樊市| 靖州| 乾安县| 保定市| 交城县| 凤凰县| 安溪县| 漳州市| 英吉沙县| 周口市| 濮阳市| 林周县| 旌德县| 资中县| 兴和县| 大竹县| 仲巴县| 和田县| 游戏| 军事| 育儿| 军事| 南通市| 涿鹿县| 郯城县| 诸暨市| 丹寨县| 绥德县|