2009-06-29 99 views
3

多線程很難。你唯一能做的就是非常小心地編程,並遵循好的建議。我從這個論壇的答案中得到的一個很好的建議是避免可變狀態。我知道這甚至在Erlang語言中被強制執行。然而,我沒有看到如何在沒有嚴重的性能命中和大量緩存的情況下完成這項工作。如何避免可變狀態(多線程時)

例如。你有一個很大的對象列表,每個對象都包含很多屬性;換句話說:一個龐大的數據結構。假設你有一堆線程,他們都需要訪問和修改列表。 如何在不共享內存的情況下完成而不必緩存每個線程中的整個數據結構?

更新:在閱讀了迄今爲止的反應之後,我想再強調一下的性能。你不認爲複製相同的數據會使程序比共享內存慢嗎?

+1

不要認爲你的程序應該是多線程的,並且如果你想讓它分佈式的話? Datastruct複製在這裏是一個很大的勝利。 – akappa 2009-06-29 09:45:45

+0

你說得對。在我們的應用程序中,用戶界面被分成一個通過TCP連接的瘦客戶機。我們將相當大一部分數據緩存在UI端。結果是更多的代碼和更復雜的程序。 – 2009-06-29 10:02:01

回答

1

我想第一個問題是:他們爲什麼需要修改列表?他們是否有可能將修改作爲修改列表返回,而不是實際修改共享列表?他們可以使用一個看起來像是原始列表的可變版本的列表,但實際上只有本地可變嗎?你在更改列表中的哪些元素,或者僅僅是這些元素的屬性?

這些只是問題而不是答案,但我試圖鼓勵你以不同的方式思考你的問題。把大局看作是你想要達到的目標,而不是考慮你以正常的必要的,可變的方式解決它的方式。改變你對問題的思考方式是非常困難的,但是你可能會發現你得到了一些很棒的「啊哈!」瞬間:)

+0

你說得對,我的例子有點含糊。我會考慮它,並試圖提出一個更好的例子。 – 2009-06-29 09:15:42

1

使用多線程和大數據集時有很多缺陷。避免可變狀態的建議旨在試圖讓你的生活更輕鬆,如果你能遵循指南(即如果你沒有可變狀態,那麼多線程將會更容易)。

如果您有大量的數據需要修改,那麼您可能無法避免可變狀態。另一種方法是將數據分成塊,每個塊都被傳遞給一個線程進行操作。該塊可以被處理並返回,然後控制器可以在必要時執行更新。在這種情況下,您已經從線程中刪除了可變狀態。

如果這不能完成,每個線程需要更新整個列表的訪問權限(即它可以隨時更新列表上的任何項目),那麼你將有很多樂趣,試圖確保你有您的鎖定策略和併發問題已排序。我確定有些情況需要這樣做,避免可變狀態的設計模式可能不適用。

+0

這是一個很好的答案。非常感謝。 – 2009-06-29 09:19:29

2

不是每種算法都可以以成功的方式並行化。

如果你的程序沒有顯示任何「並行結構」,那麼你註定要使用鎖定和共享的可變結構。

如果你的算法表現出結構,那麼你可以用一些模式或形式來表達你的計算(例如,一個宏數據流圖),它可以選擇不可變的數據結構。

所以:考慮算法的結構,而不是根據數據結構的屬性來使用。

1

只使用不可變的數據對象是一個很大的幫助。 修改列表聽起來像一個構造的參數,但考慮不知道列表的粒度方法。

+0

構建的參數? :-)當然不是。它經常出現在我有大量密切相關的數據的情況中。事實上,你可能會把它分成幾塊,但我希望這會讓程序代碼更長更復雜。 – 2009-06-29 09:24:53

1

如果您確實需要更新結構,有一種方法可以讓單個工作線程從一個互斥體獲取固定區域的更新請求。

如果你很聰明,你可以在不影響任何「讀」 線程的情況下更新結構(例如,如果添加到數組的末尾,您將完成添加新結構的所有工作,但僅限於最後一條指令是否增加NoOfMembers計數 - 讀取線程在執行此操作之前不應該看到新條目 - 或者 - 將數據排列爲對結構的引用數組 - 當要更新複製當前成員的結構時,更新它,然後作爲最後一個操作替換數組中的引用)

其他線程然後只需要檢查一個簡單的「更新進程」互斥體,只有當他們活躍地想要更新。