2016-01-23 52 views
0

我在Node JS新,我不知道是否下面提到的代碼片段有多區段的問題。是否有任何風險在節點JS中讀取/寫入不同「會話」中的相同文件內容?

考慮我有節點JS服務器(express),我聽一些POST要求:

app.post('/sync/:method', onPostRequest); 

var onPostRequest = function(req,res){ 

    // parse request and fetch email list 
    var emails = [....]; // pseudocode 

    doJob(emails); 

    res.status(200).end('OK'); 
} 

function doJob(_emails){ 

    try { 
     emailsFromFile = fs.readFileSync(FILE_PATH, "utf8") || {}; 

     if(_.isString(oldEmails)){ 
      emailsFromFile = JSON.parse(emailsFromFile); 
     } 

     _emails.forEach(function(_email){ 

      if(!emailsFromFile[_email]){ 
       emailsFromFile[_email] = 0; 
      } 
      else{ 
       emailsFromFile[_email] += 1; 
      }     
     }); 

     // write object back 
     fs.writeFileSync(FILE_PATH, JSON.stringify(emailsFromFile)); 

    } catch (e) { 
     console.error(e);    
    }; 
} 

所以doJob方法接收_emails名單,我更新(計數器+1)從對象emailsFromFile這些電子郵件從文件加載。

考慮我在同一時間得到2個請求,它觸發doJob兩次。恐怕一個請求從文件加載emailsFromFile第二個請求可能會更改文件內容。

任何人都可以在這個問題上傳播光?

回答

2

因爲doJob()函數中的代碼都是同步的,所以不會有多個請求導致併發問題的風險。

如果您在該函數中使用異步IO,那麼可能會出現併發問題。

要解釋,node.js中的Javascript是單線程的。因此,一次只有一個Javascript執行線程正在運行,並且該線程的執行會一直運行,直到它返回到事件循環。因此,像doJob()這樣的完全同步代碼的任何序列都將無中斷地完成。

如果,另一方面,你可以使用任何異步操作,如fs.readFile()代替fs.readFileSync(),然後執行線程會回到你打電話fs.readFileSync()點返回到事件循環,而這是另一個請求可以運行閱讀文件。如果是這種情況,那麼最終可能會有兩個請求在同一個文件上發生衝突。在這種情況下,您將不得不實施某種形式的併發保護(某種標誌或隊列)。這是數據庫提供大量功能的類型。

我有一個在Raspberry Pi上運行的node.js應用程序,它使用大量的異步文件I/O,並且可能與多個請求中的代碼發生衝突。我通過設置一個標誌來解決這個問題,只要我正在寫一個特定的文件和其他任何想要寫入該文件的請求,首先檢查該標誌,並且如果它被設置,那麼進入我自己的隊列中的請求就會在先前請求完成其寫入操作。還有很多其他方法可以解決這個問題。如果這種情況發生在很多地方,那麼可能值得一個數據庫提供這類寫入爭用的功能。

+0

問題是:當一個'會話'加載電子郵件計數器,讓它說'3',並運行+1,然後它將其存回,其他會話已更新此計數器,因此它實際上應該是5,但第一次會話商店4 intead –

+0

@MaximShoustin - 請再次閱讀我的答案。 'doJob()'在運行時沒有其他請求可以運行。所以在'doJob()'運行時,沒有其他任何事情可以改變會話。這是因爲'doJob()'完全是同步代碼。如果它是異步的,那將是一個不同的故事。 – jfriend00

+0

有你,謝謝 –

相關問題