2014-02-13 93 views
1

我正在嘗試同步要提供圖像的webapi。當我請求一個特定的圖像時,它會檢查圖像是否已經存在,如果有,則返回;如果不存在,則會創建並返回。.net文件訪問同步

我的問題是,它顯然不是像這樣的線程安全;我有一個線程進來,並確定圖像不存在,並開始創建它,而另一個請求進來,也確定圖像不存在(只是還),並嘗試創建它。我知道我可以鎖定整個事情以避免這個問題,但我試圖避免這個問題。將會有100,000個圖像,我不明白爲什麼我需要停止所有線程閱讀其他圖像,因爲只有一個圖像尚不存在。有沒有一種「通常」的方式來做到這一點?圖像是由ID請求的,我可以鎖定特定圖像的ID嗎?例如

List<long> _locks = new List<long>(); 
_locks.Add(17); 
lock(_locks[0]){...} 

它只是看起來不正確...肯定有更好的解決方案?

+0

你可以做的是,在你的'Read'上添加3次重試周期,相隔2秒。因此,如果您收到「文件訪問異常」,大概在寫入文件時,請等待並再次嘗試讀取。 –

+0

@ T.S。感謝隊友,我想到了這一點,我猜想這是一個「備份」解決方案,但如果可以的話,我想盡量避免出現異常。我在多線程方面沒有做太多的工作,所以試圖弄清楚如何正確地做到這一點。 嘗試鎖定一個(靜態)對象上的整個部分,平均響應時間從20ms到200ms ... !! – Andy

回答

2

這取決於您的服務器設置(單個或農場)。在單個服務器上,您可以使用共享的HashSet。文件名是一個很好的關鍵。你只需要在Set周圍設置一個簡短的鎖定,這不會影響性能。

這是一個關於concurrent HashSet

+0

這最後運作良好。它將avg響應降低到12ms - 當然lock()優於200ms,比沒有管理(因此有很多錯誤)和20ms更好。謝謝你的幫助。 – Andy

0

我的朋友的問題,你想避免「嘗試爲主」的方針,要避免「鎖定」的辦法,然而,你訪問共享資源。嘗試在任何託管的dll上調用corflags,然後離開命令窗口。然後去Windows資源管理器,並嘗試刪除該文件。你會得到「該文件正在使用」。即使Windows並沒有完全擺脫文件的束縛,還有所有的緩存機制。當然,問題是你有所有的文件通過相同的鎖。也許你可以做些什麼來最大限度地減少這種情況。讓我們來看看。這是完全未經測試的想法:

創建自定義的鎖定對象

public class CustomLock 
{ 
    private object _lock = new object(); 
    private string _file; 

    public CustomLock(string file) 
    {_file = file;} 

    public object Read() 
    { 
     lock(_lock) 
     { 
      // read your file 
     } 
    } 

    public object Read() 
    { 
     lock(_lock) 
     { 
      // read your file 
     } 
    } 

    public override int GetHashCode() 
    { 
     // here your hash algorithm 
    } 

} 

現在,使用HashTableHashTable.Synchronized這裏描述http://msdn.microsoft.com/en-us/library/system.collections.hashtable.synchronized%28v=vs.110%29.aspx,有你的鎖

或者你也可以同步字典What's the best way of implementing a thread-safe Dictionary?的緩存。所以,現在會是這樣的:

var custLock = GetCustLock(file); // This should always return CustomLock object, new or existing 
object file = custLock.Read(); 

據推測,採用這種設計,您將刪除鎖定在同一個地方的所有文件的瓶頸。請測試它。