2019年11月23日 星期六

.NET C# 單執行緒 同步 多執行緒 非同步 執行緒同步 Synchronization 邏輯處理器數量 設計探討 : Part 1 在單一執行緒下,同步執行加一與減一方法

.NET C# 單執行緒 同步 多執行緒 非同步 執行緒同步 Synchronization 邏輯處理器數量 設計探討 : Part 1 在單一執行緒下,同步執行加一與減一方法

在這篇文章所提到的專案原始碼,可以從 GitHub 下載

進行單一執行緒的測試

在我這台電腦主機上,使用的是 Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz,其具有四核心與超執行緒 Hyper Threading 的技術,因此,對於作業系統而言,將會看到這台電腦具有八核心的能力。
在這裡,將會進行這樣的計算作業,也就是 加一 +1 與 減一 -1
C Sharp / C#
class AddSub
{
    public static int counter = 0;
    public void Adds()
    {
        for (int i = 0; i < int.MaxValue; i++)
        {
            counter++;
        }
    }
    public void Subs()
    {
        for (int i = 0; i < int.MaxValue; i++)
        {
            counter--;
        }
    }
}
如同上面的程式碼,在此設計了一個類別 AddSub ,該類別提供了兩個執行個體方法與一個靜態變數,第一個物件方法 Adds 會執行一個迴圈,將會跑 int.MaxValue 次,每次回圈內將會執行 counter++ 這個表示式,這裡的 counter 是一個靜態變數,但是 counter 的數值異動卻是由執行個體方法來去變更的;第二個物件方法 Subs 會執行一個迴圈,將會跑 int.MaxValue 次,每次回圈內將會執行 counter-- 這個表示式。也就是說 Adds() 這個方法將會再回圈內每次都進行加一的動作,而對於 Subs() 這個方法將會在回圈內每次都進行減一的動作。
現在,首先要進行的測試目的為將會是要進行僅有一個執行緒的執行結果測試
C Sharp / C#
static void SyncAddSub()
{
    AddSub addSub = new AddSub();
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();
    addSub.Adds();
    addSub.Subs();
    stopwatch.Stop();
    Console.WriteLine($"Counter={AddSub.counter}, {stopwatch.ElapsedMilliseconds:N0}ms");
}
透過上面的程式碼,設計出 SyncAddSub() 方法,在這個方法內,將會使用 Stopwatch 型別提供計算執行所需要花費時間工具,當計時器開始運作的時候,便會開始同步執行 addSub.Adds(); & addSub.Subs(); 這兩個加一與減一計算工作,最後將會顯示 AddSub.counter 這個靜態變數的值為多少 (當然,正確的結果應該是要為 0) 和所耗費的時間,單位式 ms。
由於大多數的電腦大都具有多CPU或者多核心的能力,也就是說在這台電腦上將會有多個處理器可以使用,如此,便可以採用平行處理的方式,大幅提升整體電腦執行效能。
為了要了解到上面設計的單一執行緒下執行的程式,若在具有不同數量的處理器下來執行,會有甚麼樣的變化,在這裡將會透過 Process.GetCurrentProcess().ProcessorAffinity = (IntPtr) 0b10000000 ; 這樣的敘述,來指定這次執行的 .NET 程式,僅能夠限制使用多少顆處理器數量,從這個例子中,經會限制這次執行的程式,僅能夠使用一顆處理器。
為了要方便測試,這裡將會把所有需要測試的步驟,都設計在同一個專案程式碼內,ThreadSynchronization,透過者個專案程式,僅需要在執行的時候,提供不同的引數,就可以做到不同的執行效果,底下是使用方式說明
使用方式 : ThreadSynchronization 多執行緒模式 計算方式 使用CPU模式
多執行緒模式 : Yes , No
計算方式 : NoLock , UserModeLock , UsingNETLock , NoLockByLocal
使用CPU模式 : 1000000 , 11000000 , 10100000 , 11110000 , 10101000
第一個參數將會指定是否要使用多執行緒的方式來執行測試,也就是加一這個方法將會在執行緒 Thread A 中來執行,而減一這個方法將會安排在執行緒 Thread B 中來執行;若在此提供的參數值為 no,則表示加一與減一這兩個方法,都會在同一個執行緒來執行。
第二個參數將會指定要使用哪種 執行緒 同步 Thread Synchronization 機制來設計出執行緒安全 Thread Safe 的程式碼,也就是同樣的程式碼,在多執行緒環境下跑出來的結果,不論執行幾次,執行結果都是可以預期的,也就是結果將會是正確的,沒有模稜兩可問題產生;其中 NoLock 將會不使用任何的執行緒同步機制,當然,將會有可能造成執行緒不安全的問題、UserModeLock 將會使用 User Mode 使用者模式下的執行緒同步機制,這裡將會使用 Interlocked 這個類別來做到、UsingNETLock 這個參數指定使用 C# lock 關鍵字來做到關鍵區域 Critical Section 關鍵區域在同一個時間內,僅會有一個執行緒可以執行這段程式碼、NoLockByLocal 將會在多執行緒執行過程中,當在迴圈跑的時候,不會去變更共用靜態變數,而是在迴圈跑完之後,才會來將累加結果,更新到共用靜態變數內,而在這裡將會透過 Interlocked 這個類別來做到 執行緒安全 的目的。
第三個參數則是用來指定所要使用的處理器 Processor 的數量,要使用這個參數是要確認,當成是於單執行緒 同步執行 或者多執行緒 非同步執行下,若使用不同的處理器數量,是否會有造成甚麼影響;當使用了 Process.GetCurrentProcess().ProcessorAffinity = (IntPtr) 0b10000000 ; 這個敘述,表示指定使用該核心內的一個處理器來進行運算,並不是使用到電腦上所有可用的處理器,而當使用了 Process.GetCurrentProcess().ProcessorAffinity = (IntPtr) 0b11000000 ; ,則設定使用同一個處理器硬體核心,不過,對於這裡指定兩個處理器,將會採用 Hyper-Threading 技術來運行,根據 Intel 的說明,當採用 Hyper-Threading 技術,可以提升約 20% ~ 30% 的執行效能;若使用了 Process.GetCurrentProcess().ProcessorAffinity = (IntPtr) 0b10100000 ; 敘述,則是指定了兩個核心處理器作為此次程式要運算的處理器。
現在,請將這篇文章所提到的範例程式,請先使用 Release 建置模式來建置這個專案,接著,下達這樣的指令 ThreadSynchronization no NoLock 10000000
這裡將會先來檢測僅使用單一執行緒來進行加一與減一計算工作,不過,這裡將會指定使用不同的處理器數量,底下是測試結果(在不同的電腦上,因為 CPU 硬體規格不盡相同,所以,可能需要依據讀者本身的可用處理器數量,自行調整第三個參數的內容。
想要確認可用處理器數量,可以打開 Windows 電腦的工作管理員,切換到 [效能] 標籤頁次,在該頁次右下方將會看到 [邏輯處理器] 這個文字標籤的右邊,就是這台電腦上可用的處理器數量,在這台電腦上實際上為單一一顆CPU硬體,但是具有 4 Core 四核心,而且每個核心都有採用 Hyper Threading 的技術,因此,對於整體電腦而言,將會有 8 顆處理器數量,也就是這裡所提到的 邏輯處理器 數量。
底下將會指定在單一執行緒下,同步執行加一與減一方法,並且指定在不同的邏輯處理器數量下的執行結果。
ThreadSynchronization no NoLock 10000000
Counter=0, 7,515ms

ThreadSynchronization no NoLock 10100000
Counter=0, 7,477ms

ThreadSynchronization no NoLock 10101000
Counter=0, 7,458ms

ThreadSynchronization no NoLock 11000000
Counter=0, 7,410ms

ThreadSynchronization no NoLock 11100000
Counter=0, 7,468ms

ThreadSynchronization no NoLock 11110000
Counter=0, 7,497ms

ThreadSynchronization no NoLock 11111111
Counter=0, 7,670ms
從上面的執行結果可以看的出來,若在單一執行緒下,同步執行加一與減一方法,最終的計算結果,也就是 Counter 這個靜態變數的內容將都會是 0,這是正確與可以預期的結果,而且不論使用多少的邏輯處理器數量,所得到的結果都是相當的;這也就是說,若設計的程式採用單一執行緒的同步方式來執行,將不會有執行緒不安全的問題,而且執行上所花費的時間將不會明顯的影響。



2019年10月31日 星期四

Github 快速上手 2 : 建立新的 Repository 與 同步

Github 快速上手 2 : 建立新的 Repository 與 同步

在 Github 建立一個新的 Repository

請打開 Github 網頁,於登入認證之後,點選右上方的 + 加號 圖片
當 [Create a new repository] 頁面出現之後,請在 [Repository name] 這個欄位中,輸入想要建立的 Repository 的名稱,這裡會輸入 MyFirstRepository
使用滑鼠捲動網頁到最下方,將會看到 [Create respository] 這個按鈕,請點選這個按鈕,完成這個 Repository 的建立。

複製 Github 的 Repository 到本機電腦上

現在完成了這個 MyFirstRepository 這個 Repository 的建立,現在,請在 [Quick setup — if you’ve done this kind of thing before] 標題的下方,將會看到一個 HTTS URL,請將這個 URL 複製到系統剪貼簿內。
請打開檔案總管,切換到想要儲存這個 Repository 的目錄內,這裡是切換到這台電腦的 [C:\Xamarin] 目錄內;接著,在檔案總管空白地方,使用滑鼠右擊,現在將會看到彈出功能表中有個 [Git Clone...] 這個選項,請點選這個選項。
現在, [TortoiseGit] 將會使用系統剪貼簿內儲存的 URL,複製一份遠端 Github 上的 Repository 到這台電腦上的這個目錄內。
當出現了 [Git clone] 對話窗的時候,可以直接使用預設值 ( 因為,對於 URL 欄位的內容,將會從剪貼簿取得 ),接著請點選 [OK] 按鈕

設定 Repository 簽入 Commit 要排出的檔案類型

現在請切換到這個 Repository 的目錄下,也就是 [C:\Xamarin\MyFirstRepository] 這個目錄,並且建立一個 [.gitignore] 文字檔案。
該 [.gitignore] 的檔案內容,可以從 https://raw.githubusercontent.com/vulcanlee/CSharp2019/master/.gitignore 取得
上面螢幕截圖為建立 [.gitignore] 文字檔案 與 加入該檔案內容的操作結果。
現在可以進行第一次的 簽入 Commit,請在這個 Repository 目錄內的空白地方,點選滑鼠右鍵,從彈出功能表中選擇 [Git Commit -> "master"] 這個選項
當 [C:\Xamarin\MyFirstRepository - Commit - TortoiseGit] 對話窗出現之後,請在 [Message] 欄位中輸入 Init (或者任何代表此次簽入的文字內容)。
在下方的 [Changes made (double-click on file for diff)] 標題下方,點選 [All] 文字,代表要選擇所有當前所有的檔案。
最後,找到下方的 [Commit] 按鈕,請先點選該按鈕右方的 向下黑色三角形 ,此時會出現一個彈出選單,請在該選單內選擇 [Commit & Push] ,表示,按下這個按鈕之後,將會進行簽入與推入到遠端的 Github 主機內。
當進行第一次操作的時候,將會如上面螢幕截圖,要求第一次要先進行 Github 身分驗證,在這裡,請輸入剛剛申請 Github 的帳號(或者Email)和密碼之後,點選 [Github Login] 對話窗下方的 [Login] 按鈕。
當看到如上面螢幕截圖,這就表示這次的簽入與推入到遠端 Github Repository 的工作已經完成了。
從網頁中將會看到剛剛增加的 [.gitignore] 檔案已經成功地簽入到 Github Repository 內了。

將 Xamarin.Forms 的方案內所有專案,簽入到 Github Repository 內

現在可以找出一個正在開發或者新建立的 Xamarin.Forms 專案,不過,最好這個專案是可以正常建置與執行的,因為,這裡需要這些專案內的 Bin Obj 目錄下的這些二進位元檔案。
在這裡已經複製一份 CustNaviService 之 Xamarin.Forms 的方案,根據檔案總管的統計,這個 CustNaviService 目錄下總共有 182MB 磁碟空間,可是,真正的原始碼並沒有這麼多,絕大多數是由二進位檔案所佔據。
在此之前,已經 簽入 Commit 這個 [.gitignore] 檔案,因此,當要繼續簽入這個專案檔案內容的時候,將會排除這些 二進位 型態的檔案,現在,來檢驗看看。
請在檔案總管確認是在 [C:\Xamarin\MyFirstRepository] 目錄下,使用滑鼠右鍵點選空白地方,當彈出功能表出現的時候,請選擇 [Git Commit -> "master"] 這個選項,準備簽入與推入到 Github Repository 內
在出現了 [C:\Xamarin\MyFirstRepository - Commit - TortoiseGit] 對話窗的時候,請在 [Message] 欄位內輸入 [加入 CustNaviService 方案所有檔案] 簽入備註訊息,並且在下方點選 [All] 文字,選擇所有的檔案內容。
若此時使用滑鼠捲動最下方的檔案清單內容,應該不會看到任何 二進位元 類型的檔案。
最後,請點選 [Commit & Push] 按鈕,進行簽入與推入到Github Repository。
當完成簽入與推入之後,將會看到如上圖的畫面。

確認推入的專案,將不包含二進位元的檔案

先打開 Github 網站中的 MyFirstRepository Repository,檢查剛剛推入的檔案是否已經推進去了。
打開 https://github.com/XamarinForms/MyFirstRepository 網頁,在下方就會看到 [CustNaviService] 目錄已經在 Github 的 Repository 內了。
請使用滑鼠來點選上面截圖的紅色箭頭指向的按鈕,也就是 [Clone or download] 按鈕
當彈出了 [Clone with HTTPS] 視窗的時候,請將該子視窗內的 URL 複製起來。這裡的 URL 將會是 : https://github.com/XamarinForms/MyFirstRepository.git
現在請使用檔案總管切換到 C:\Xamarin 這個目錄下
在該目錄的空白地方,使用滑鼠右鍵點選 [Git Clone...] 這個選項
當出現了 [Git clone - TortoiseGit] 這個對話窗,請將 [Directory] 這個欄位,輸入成為 C:\Xamarin\MyFirstRepository2
也就是要複製一份 Github 上的 Repository,不過,是要複製到 C:\Xamarin\MyFirstRepository2 這個目錄下 (原先剛剛的 Repository 是複製到 C:\Xamarin\MyFirstRepository 目錄下)
最後,請點選 [OK] 按鈕,開始進行複製
完成複製後,請在 [C:\Xamarin - Git Command Program - TortoiseGit] 對話窗內,點選 [Close] 按鈕
從上面操作螢幕截圖中,可以看到 [MyFirstRepository2] 這個目錄已經產生出來了。
請使用檔案總管,查看 [C:\Xamarin\MyFirstRepository2\CustNaviService] 目錄的內容,發現到 [CustNaviService] 這個目錄下,僅佔有 1.32 MB 大小,這與之前查詢 [C:\Xamarin\MyFirstRepository\CustNaviService] 目錄所站的空間為 182MB 有很大的落差,這是因為絕大部分的檔案都是二進位元的檔案,而且在簽入的時候都已經排出掉了,不會簽入到 Github Repository 內。

清除本機 Repository 內的二進位元檔案

現在,請使用檔案總管回到 [C:\Xamarin\MyFirstRepository] 目錄下,準備把這些二進位元的檔案清除掉,順便檢查清除後的專案所佔據的磁碟空間。
請在 [C:\Xamarin\MyFirstRepository] 目錄下,使用滑鼠右擊空白地方,當彈出選單出現之後,依據點選 [TortoiseGit] > [Clean up...] 選項
現在出現了 [C:\Xamarin\MyFirstRepository - Clean - TortoiseGit] 這個對話窗,相關的選項請使用預設值,直接點選 [OK] 按鈕
現在請使用檔案總管來查看 [C:\Xamarin\MyFirstRepository\CustNaviService] 目錄的內容,從上面螢幕截圖中,可以看到,這些二進位元檔案也都被移除了,整個 [C:\Xamarin\MyFirstRepository\CustNaviService] 目錄僅佔有 1.32 MB
請注意
在使用這個功能的時候,請記得這個 Repository 已經完成了 簽入 Commit 動作




2019年10月30日 星期三

Github 快速上手 1 : 環境的安裝與設定

Github 快速上手 1 : 環境的安裝與設定

當我在進行 Xamarin.Forms 課程教學的時候,當學員所練習的專案有問題時候,我都會建議學員把專案原始碼提供給我,好方便進行除錯,可是,通常學員給我的該練習專案的壓縮檔案都非常大,幾乎超過 80MB 以上、甚至更大,而,就算請學員把專案原始碼推入到 Github Repository 上,該 Repository 的檔案體積也是十分的大;這是因為在進行 git commit 簽入時候,把許多二進位元檔案也簽入進去了,而這些二進位元檔案是 Visual Studio 在建置時期產生的,其實不需要簽入或者儲存起來,因為,下次建置的時候,就會重新產生出來了。
因此,在這裡撰寫了兩篇系列文章,方便學員參考了解 Github 這個工具的使用過程
這裡將會說明如何在第一次使用 Github 功能的時候,如何申請帳號、安裝相關軟體、進行設定
這裡將會說明如何建立 Github Repository、複製該 Repository 到本機電腦內、簽入忽略二進位元的設定到 Github Repository 內、簽入 Xamarin.Forms 的專案、使用 TortoiseGit 工具清除本機 Repository 內的二進位元檔案。
在這系列文章中,假設開發者已經有安裝了 Visual Studio 2017 或者 Visual Studio 2019 開發工具。

申請 Github 帳號

若還沒有 Github 帳號,可以參考底下的步驟來進行申請,若已經有 Github 帳號,則可以跳過有關 Github 帳號申請說明的內容,直接進入到下一段內容。
在打開 Github 網站之後,將會看到該網頁的左方有 [Username] 、 [Email] 、 [Passowrd] 三個文字輸入盒,請在這裡輸入你自己的相關資訊,完成後,請點選 [Sing Up for Github] 這個按鈕,申請一個免費的 Github 帳號。
此時,Github 網站需要進行驗證,請點選中間的 [驗證] 按鈕
請依照網頁文字說明指示內容進行操作,完成後,將會看到如上圖的文字,表示驗證完成,此時,可以點選螢幕上的 [完成] 按鈕。
現在,可以點選下方的 [Next: Select a plan] 按鈕,不過,在這裡有勾選 Email preferences 的選項 [Send me occasional product updates, announcements, and offers.]
在此,可以選擇免費 [Free] 的方案即可,請點選 [Choose Free] 這個按鈕
當看到歡迎來到 Github 網站的訊息,請使用滑鼠轉動到最下方。
在這裡將可以點選 [Complete setup] 按鈕,不過,將會使用直接點選 [Skit this setp]
好的,請檢查剛剛申請帳號使用的 Email 信箱,打開 Github 寄送來的驗證郵件
請點選郵件上的 [Verify email address] 藍色按鈕,或者底下的 URL 連結
現在已經完成了 Github 帳號的申請作業了

確認與 Git for Windows 有安裝

請先確認電腦中是否已經有安裝 Git for Windows
在桌面左下角,點選放大鏡或者在 [搜尋方塊] 中輸入 git 文字,若這個時候沒有找到任何應用程式,那就表示這台電腦上還沒有安裝 [Git for Windows] 這個應用程式。
若沒有的話,可以透過 Visual Studio Installer 工具來協助安裝。
Visual Studio Installer
在電腦中找到 [Visual Studio Installer] 這個應用程式
當 Visual Studio Installer 安裝程式啟動起來之後,請點選 [個別元件] 標籤頁次,可以在 [程式碼工具] 區段中,找到 [Git for Windows] 這個選項,若該選項尚未勾選,請勾選這個選項,把它安裝起來。
現在再度在桌面左下角,點選放大鏡或者在 [搜尋方塊] 中輸入 git 文字,此時將會看到上面的螢幕截圖,表示這電腦上已經有安裝 [Git for Windows] 這個應用程式。

安裝 TortoiseGit

為了要能夠透過 [檔案總管] 來進行 [Github] 的同步與操作更多功能,在這裡可以先安裝 [TortoiseGit] 這個工具;請先使用瀏覽器打開這個網址 https://tortoisegit.org/
在 [TortoiseGit] 網頁上,將會看到 [Download] 按鈕,請點選這個按鈕
當 [Download] 網頁出現之後,可以選擇 [for 64-bit Windows] 文字下方的檔案下載連結,這裡看到的是 Download TortoiseGit 2.8.0 - 64-bit 準備下載與進行安裝這個工具。
[TortoiseGit] 安裝程式啟動之後,請點選 [Next] 按鈕
在 [Information] 對話窗中,點選 [Next] 這個按鈕
在 [Choose SSH Client] 對話窗中,使用預設值,點選 [Next] 這個按鈕
在 [Custom Setup] 對話窗中,使用預設值,點選 [Next] 這個按鈕
在 [Ready to Install] 對話窗中,點選 [Install] 這個按鈕,準備開始進行安裝作業。
現在已經安裝完成了,請點選 [Finish] 按鈕,準備進行第一次精靈的設定
在 [Welcome to TortoiseGit] 對話窗中,使用預設值,點選 [下一步] 這個按鈕
在 [Welcome to TortoiseGit] 對話窗中,使用預設值,點選 [下一步] 這個按鈕
在 [Configure git.exe] 對話窗中,點選中間右方的 [Check now] 按鈕,此時,在該按鈕的左方會出現這台電腦已經安裝 Git 工具版本,這裡顯示的是 [git version 2.17.1.windows.2] ,最後請點選 [下一步] 這個按鈕
在 [Configure user information] 對話窗中,請在 [Name] 與 [Email] 欄位中,輸入你的相關資訊,點選 [Next] 這個按鈕
在 [Authentication and credential store] 對話窗中,使用預設值,點選 [完成] 這個按鈕
在 [Information] 對話窗中,使用預設值,點選 [Next] 這個按鈕