2017-04-13 41 views
1

很多文章說:不要使用鎖來同步長操作,我遵循這個規則。但我很好奇,究竟是什麼錯誤呢?這是關於一些寶貴的資源消耗?爲什麼C#鎖定不應該用於長時間操作?

此外,將幫助它,如果我使用的AutoResetEvent呢?或者我應該忘記鎖定長操作並進行異步編程?

+0

請張貼一些代碼什麼是你想達到 –

+0

我猜職位是意味着是一個更具普遍性的問題。 – Moerwald

回答

15

首先,如果你不明白該規則的原因,那麼你就貨物崇拜編程。這是至關重要,你明白這些規則的原因,而不是盲目應用。

所以,兩個原因持有鎖的時間短量:

(1)長鎖等表現不佳。假設您有一次只有一個人可以使用的資源。你真的想讓你的室友在洗澡的時候做稅收和看Netflix嗎?不,你希望他們進入和離開,以便其他人可以使用它。

(2)長鎖等於死鎖。如果你長時間處於鎖定狀態,那麼你可能會調用很多代碼。這會增加您調用的代碼具有您不知道的鎖定順序反轉的機率。

因此,標準的建議是:鎖,因爲沒有時間成爲可能,並有許多細粒度鎖,而不是單一的粗粒度鎖。

當然,標準諮詢的是,有許多細粒度鎖增加機會死鎖,因爲現在你有可能被顛倒的鎖。並且擁有許多細密的鎖也增加了存在未知競爭的可能性,即在您未考慮的兩個鎖定區域之間運行某些事情。所以標準的建議是:擁有少量的粗粒鎖,可以鎖定大部分代碼。

標準的建議是矛盾的。這是爲什麼?因爲通過監視器鎖定管理多線程程序中的共享內存根本上是一個壞主意。這是標準的做法,但這並不是很好。

此外,如果我使用AutoResetEvent,它會幫助嗎?或者我應該忘記鎖定長操作並進行異步編程?

我的建議是使用最高級別的操作就可以了。如果你可以逃避並不異步,那就去做吧。如果不是,請考慮進程級並行或單線程異步,具體取決於處理器綁定還是IO延遲綁定。如果這些因爲任何原因而不起作用,則將線程作爲輕量級進程與共享內存;使用TPL爲您管理您的線程。

依此類推。處理鎖或互鎖操作或揮發物應該是最後的手段,並且這些工具應該被用作原語來構建更高級別的工具。

+1

本質是使用高級抽象,TPL,併發集合,儘量不再使用像'lock','EventWaitHandle'這樣的低級構造。抽象在管理資源方面做得更好。 –

+0

如果性能或死鎖不成問題會怎樣?也許你只想讓鎖序列化多個任務。它還不好嗎?可以說我有N個任務由定時器觸發。它們不是時間關鍵的,但重要的是它們不會同時運行。如果我只是用全局鎖包圍每個任務,我會遇到資源問題還是其他問題?如果任務需要1秒,10秒,10分鐘,這有什麼關係? (我知道有其他方法可以解決它) – adrianm

+3

@adrianm:你的問題是:如果我們說「在我們的場景中沒有問題」,那麼是否有問題?不,如果你不關心性能或正確性,那麼根據定義,你沒有性能或正確性問題。 –

1

簡單的想法背後。 Lock本質上阻止其他線程進入臨界區。說關鍵部分已經有一個thread這是做一些工作,然後另一個線程正在等待訪問關鍵部分。這使得這些threads在一個問題上同步執行。這就產生了一個問題,爲什麼你不使用單線程呢?

所以第一個原因是你可能會爲它運行單線程。

另一點,通過使關鍵部分長操作,您還阻止等待鎖定的所有其他線程被解除,從而潛在地增加了執行時間的代碼量thread

第二個原因,你的代碼在高度併發的環境下會非常慢。

0

也許長鎖的另一個重要的事情 - >優先倒置(見link)。我們來考慮以下幾點。

低prio線程鎖定資源很長一段時間。高級prio線程還需要訪問此資源。最壞的情況:低prio線程持有鎖,高prio線程啓動並訪問鎖。在這種情況下,低prio線程計劃爲「不活動」,高prio線程計劃爲「活動」。問題:高級螺紋被阻塞,因爲低級螺紋仍然保持鎖定。

我知道這個問題在閱讀時很明顯,但在複雜的代碼中並不總是那麼清楚......減少鎖定範圍可以幫助避免這種情況。

如果可能切換到異步,但也要注意也有可能發生死鎖情況(例如,請參閱此post)。

0

C#鎖定語句用於限制從多個線程訪問關鍵部分。該語句確保對單個線程執行的互斥訪問,直到釋放鎖。例如,如果文件寫入條件設置爲在寫入操作正在進行時阻止所有訪問,則圍繞文件寫入代碼的包裝鎖定語句確保滿足條件。

現在,如果執行時間變長,其他線程排隊等待鎖定。這導致響應時間緩慢,性能下降或者由於超時導致呼叫失敗。示例 -

private Object lockObj = new Object(); 

public void FileOperation(decimal amount) 
{ 
    //Subsequent thread calls will queue up 
    lock (lockObj) 
    {   
     using (System.IO.StreamWriter file = 
       new System.IO.StreamWriter(@"C:\Users\Public\TestFolder\WriteLines2.txt", true)) 
      { 
       //Long running operation 
       for(var i = 1; i < 1000000; i++) 
       { 
        file.WriteLine("Fourth line"); 
       } 
      } 
    } 
} 

Original Post

相關問題