2017-01-10 40 views
0

我是Node新手,我正在構建一個依賴於文件系統的小應用。如何確定兩個客戶端沒有同時請求損壞狀態

比方說,我的應用程序的目標是,以填補一個文件是這樣的:

1 
2 
3 
4 
.. 

而且我想,在每一個請求,一個新行被寫入文件,並以正確的順序。

我可以做到嗎?

我知道我不能讓我的問題在這裏沒有做任何代碼,所以在這裏。我使用的是快速JS服務器:

(我們可以想象,此文件只包含1在第一代碼發射)

import express from 'express' 
import fs from 'fs' 

let app = express(); 

app.all('*', function (req, res, next) { 
    // At every request, I want to write my file 
    writeFile() 
    next() 
}) 

app.get('/', function(req,res) { 
    res.send('Hello World') 
}) 

app.listen(3000, function (req,res) { 
    console.log('listening on port 3000') 
}) 

function writeFile() { 
    // I get the file 
    let content = fs.readFileSync('myfile.txt','utf-8') 

    // I get an array of the numbers 
    let numbers = content.split('\n').map(item => { 
     return parseInt(item) 
    }) 

    // I compute the new number and push it to the list 
    let new_number = numbers[numbers.length - 1] + 1 
    numbers.push(new_number) 

    // I write back the file 
    fs.writeFileSync('myfile.txt',numbers.join('\n')) 
} 

我試圖讓對讓我在想,我在同步過程中的猜測確信沒有別的在同一時刻做,但我真的很注意確保...

如果我不清楚,請你告訴我在評論

+0

這是一個XY問題還是你真的只是寫一個遞增的數字文件? – mscdex

+0

看完定義之後,我想這可能是。但是解決這個問題真的會幫助我理解節點的行爲。 – Hammerbot

回答

2

如果我理解正確的,你,你這是害怕是race condition發生在這種情況下,如果兩個客戶端同時到達HTTP服務器,則該文件將保存爲相同的內容,其中數字只會增加一次而不是兩次。

簡單的修復方法是確保共享資源一次只能訪問或修改一次。在這種情況下,使用同步方法可以解決您的問題。當他們正在執行時,整個節點進程被阻塞,並且不會執行任何操作。

如果您更改其異步計數器部件的同步方法而沒有任何其他併發控制措施,那麼您的代碼肯定容易受到競爭條件或損壞狀態的影響。

現在,如果這只是您的應用程序正在做的事情,可能最好保持這種方式,因爲它非常簡單,但假設您想要添加其他功能,在這種情況下,您可能希望避免任何同步方法,因爲它阻止了進程並且不會讓你有任何併發​​。

添加併發控制的一個簡單方法是有一個跟蹤有多少請求排隊的計數器。如果沒有排隊(counter === 0),那麼我們只是讀取和寫入文件,否則我們將添加到計數器。一旦寫入文件完成後,我們從計數器減少重複:

app.all('*', function (req, res, next) { 
    // At every request, I want to write my file 
    writeFile(); 
    next(); 
}); 

let counter = 0; 

function writeFile() { 
    if (counter === 0) { 
    work(function onWriteFileDone() { 
     counter--; 
     if (counter > 0) { 
     work(); 
     } 
    }); 
    } else { 
    counter++; 
    } 

    function work(callback) { 
    // I get the file 
    let content = fs.readFile('myfile.txt','utf-8', function (err, content) { 
     // ignore the error because life is too short on stackoverflow questions... 

     // I get an array of the numbers 
     let numbers = content.split('\n').map(parseInt); 

     // I compute the new number and push it to the list 
     let new_number = numbers[numbers.length - 1] + 1; 
     numbers.push(new_number); 

     // I write back the file 
     fs.writeFile('myfile.txt',numbers.join('\n'), callback); 
    }); 
    } 
} 

當然這個功能沒有任何參數,但如果你想添加到它,你必須使用一個隊列,而不是將參數存儲在隊列中的計數器。

現在不要編寫自己的併發機制。節點生態系統中有很多。例如,您可以使用async module, which provide a queue

請注意,如果您一次只有一個進程,那麼自從In節點後,您不必擔心多個線程。js,在一個進程中,一次只有一個執行線程,但假設有多個進程寫入文件,那麼這可能會使事情變得更加複雜,但如果還沒有涉及到其他問題,我們可以繼續討論。操作系統提供了幾種不同的方式來處理這個問題,也可以使用自己的鎖定文件或專用的進程寫入文件或消息隊列進程。

相關問題