天天看點

全局變量是“萬惡之源”,慎用

正在看一個老項目的代碼,滿篇都是全局變量,整個邏輯真的是“意大利面條”,不曉得這些全局變量什麼時候被改變,什麼時候被調用,恨透了全局變量和傳遞引用(傳遞引用适可而止也就罷了,傳遞個4,5層,鬼知道變量什麼時候被改變)。

下面是一些對全局變量的觀點,基本上一緻,全局變量用好省事,濫用麻煩,是以慎用。

TBOB:

不止一次地看到人們在抱怨,全局變量是罪惡之源,根本就不應該使用它們。但是我不認為這個結論是顯而易見正确的。我希望能聽到一次有關全局變量的嚴肅認真的讨論。論壇中的朋友們很多都提到了他們都正在程式設計中使用全局變量。

先從全局變量的有點談起。一般來說,全局變量是公認的在各個VI之間傳遞資料的有效方法,比起其它方式的全局變量(個人意見)更容易管理,因為假如我們使用了一個簇作為全局資料,我們沒有辦法确定在何處使用了它們,可能需要自己建立一個檔案記錄它們使用的位置。但是全局變量則不然,通過全局變量的右鍵快捷菜單,我們可以很容找到引用全局變量的位置。

使用全局變量有兩個不利之處,其一,引用全局變量需要建立資料的拷貝,這可能會導緻潛在的競争條件或者導緻資料的丢失。其二,使用全局變量會中斷資料流程。

是以,我對那些反對使用全局變量的人士提出一個問題---你們在應用全局變量時考慮了全局變量是否有效的問題了嗎?

如果對全局變量隻有一個寫入者,而有多處讀取者,您僅僅關心變量的最新寫入值的情況下,您怎麼能斷定不能使用全局變量呢?

------------------------------------------------------------------------------------------------------------------

Darren:

全局變量在某些情況下是非常好用的。如果我有一些靜态資料,這些靜态資料必須在多個VI中共享,這種情況下,我會使用全局變量存儲這些靜态資料。(所謂靜态資料就是不需要改變的資料,常量)。最常見的例子是需要給使用者提示的文本字元串。如果我有一個非常複雜的GUI,需要在很多地方向使用者提示文本資訊。我會建立一個全局變量VI,把這些字元串建立為全局變量,并且按照字母順序排序(通過設定TAB ORDER)。這樣我們需要在程式框圖中使用全局變量時,直接拖入并選擇我們需要的。這種方法可以很容易使我們的應用程式本地化,因為所有的顯示字元串集中在一個VI之中,而不是散布在各個VI之中,很容易集中處理。

我另外一次使用全局變量是在一個子面闆應用中,因為我的子面闆中的VI不需要和主VI交換資訊,是以我将子面闆VI中的資料寫入全局變量,供應用程式其它部分讀取。因為不需要同步化以及隻有子面闆中的VI寫入資料,保證了隻有一個寫入者,這恰恰是全局變量的最佳工作方式。

------------------------------------------------------------------------------------------------------------------

TBOB:

很高興能看到同人談及如何恰當地使用全局變量,而不是簡單地說完全不要使用全局變量。我們更應該強調如何恰當地使用全局變量,幫助人們了解資料競争是如何産生的,以及如何避免競争情況出現。

我大多數使用全局變量時,是把全局變量作為常量來使用的,比如儲存一個GPIB的位址。它們一旦建立後就永遠不會再次寫入更改,這種情況下,絕對不會出現資料競争的情況。或者在生産消費者模式中,生産者寫入全局變量,而消費者讀取全局變量。這種情況下,讀的時機是非常重要的。我使消費者不斷查詢全局變量,是否和原來的值發生變化。換句話說,消費者在資料更新之前可能讀取了兩次,當然并不很理想。

對于局部變量也是如此,總有它們合适使用的場合,但是必須小心可能會導緻的問題。教會人們發現問題和解決問題好于僅僅說避免使用它們。

------------------------------------------------------------------------------------------------------------------

Jasonhill:

我也經常看到要求禁止使用全局變量,在合适的條件下,使用全局變量還是非常有用的。但是程式員還是會不自覺地傾向于濫用它們,任何變量(全局變量、局部變量、LV2全局變量)在使用時需要格外小心,“連線”還是最安全的。

我非常讨厭上下或者左右堆積大量的控件,在程式框圖中多達20幾個層疊順序結構中,到處散布一些全局變量或者局部變量。

至于你提及的生産者消費者模式,我還是願意使用隊列來完成,使用隊列可以使我們不需要考慮讀的時機問題。

------------------------------------------------------------------------------------------------------------------

TBOB

在生産者消費者模式中,使用隊列(我也傾向于使用隊列,而不是變量)同樣存在問題。消費者可能運作速度高于消費者,此時可能讀回空資料,必須在程式設計中檢查是否是否讀回空資料。

------------------------------------------------------------------------------------------------------------------

TST:

在生産消費者模式使用隊列時,我願意使用逾時的預設值-1,這意味着消費者在沒有資料時不會執行一個循環,也不需要檢查逾時是否發生了。

------------------------------------------------------------------------------------------------------------------

TITOU:

真是個好題目!

全局變量是魔鬼嗎?------我願意這樣回答:不是,隻要你遵循了全局變量的工作規則。

我經常建議避免使用全局變量,但是的确在特定的場合,我還是會使用全局變量,因為使用全局變量的确非常友善。

使用但不要濫用------------------------------------------------------------------------------------------------------------------

ROBERT:

即使在基于文本的程式設計語言中,采用封裝和抽象本身就傾向于不使用全局變量。理想的結構應該是這樣的,如果函數需要一個變量,必須從函數的調用者哪裡接收這個變量。盡管如此,即使在這樣的程式設計環境中,還是需要有限度的和合理的利用全局變量。正如上面的文章中指出的那樣,一個寫入者,多個讀取者。亦或需要在整個程式應用,但是不需要改變的場合。

我經常采樣下面的方式。在程式啟動時,先運作一個配置函數或者“參數設定”函數,此時沒有其它的程序工作,資料采集也尚未進行。此時為程式的其它部分建立全局變量是合理的。

------------------------------------------------------------------------------------------------------------------

KEVIN:

我在程式開發時,習慣于在多個消費者情況下使用“通告”。通常情況下,隻有一個生産者。但是像全局變量情況,可能會有幾個“潛在”的生産者。

對于使用通告,消費者可以進行選擇。通告可以不管消費這是否已經消費了先前的資料,随時查詢最新的資料,這類似于全局變量。通告也可以一直等待,直至有最新更新的資料,避免不斷的輪詢資料,加重CPU的負擔,這個是全局變量無法實作的。

-----------------------------------------------------------------------------------------------------------------

BEN:

很抱歉沒能早點參與這個話題的讨論。我并非求全責備,但是全局變量存在下列主要問題:

1、資料拷貝

2、利用線程

3、對于一個寫入者,多個讀取者,OK.但是這要求開發者必須确認隻有唯一一個寫入者。這對一個擁有800多個VI,有些是動态載入的情況下,是很難做到的。

4、靈活性 。如果你使用一個LV2型全局變量,需要的情況下,你可以很安全地添加新的新的寫入者。在編寫大型應用時,這的确是令人頭疼的問題。

5、性能。LV2全局變量可以很容易重用緩存,全局變量不行。

-----------------------------------------------------------------------------------------------------------------

RAY:

我同意大家的看法。我通常用全局變量保持靜态資料,比如IP位址。

繼續閱讀