1. 程式人生 > >C#中多執行緒中變數研究

C#中多執行緒中變數研究

今天在知乎上看到一個問題【為什麼在同一程序中建立不同執行緒,但執行緒各自的變數無法線上程間互相訪問?】。在多執行緒中,每個執行緒都是獨立執行的,不同的執行緒有可能是同一段程式碼,但不會是同一作用域,所以不會共享。而共享記憶體,並沒有作用域之分,同一程序內,不管什麼執行緒都可以通過同一虛擬記憶體地址來訪問,不同程序也可以通過ipc等方式共享記憶體資料。全域性變數:任何執行緒都可以訪問;區域性變數(棧變數):任何執行緒執行到該函式時均可訪問,函式外不可訪問;執行緒變數:每個執行緒只能訪問自己的那個拷貝,其他執行緒不可見。今天就用C#來實現同一段程式碼的不同執行緒,全域性變數、區域性變數、執行緒變數。

瞭解程序與執行緒

什麼是多工,簡單來說就是作業系統同時可以執行多個任務。例如:一遍聽歌,一遍寫文件等。多核CPU可以執行多工,但是單核CPU也可以執行多工,CPU是順序執行的,作業系統讓任務輪流執行,例如:聽歌執行一次,停頓0.01s,寫文件執行一次,停頓0.01s等等。由於CPU的執行速度很快,我們感覺就像所有的任務都是同時執行。對作業系統來說,一個任務就是一個程序,一個程序至少有一個執行緒。程序是資源分配的最小單位,執行緒是CPU排程的最小單位。

普通的程式寫法

private static List<int> data = Enumerable.Range(1, 1000).ToList();

public static void SimpleTest()
{
    for (int i = 0; i < 10; i++)
    {
        List<int> tempData = new List<int>();
        foreach (var d in data)
        {
            tempData.Add(d);
        }
        Console.WriteLine($"i:{i},合計:{data.Sum()},是否相等:{data.Sum() == tempData.Sum()}");
    }

    Console.WriteLine("單執行緒執行結束");
}

多執行緒寫法

private static List<int> data = Enumerable.Range(1, 1000).ToList();

public static async Task MoreTaskTestAsync()
{
    List<Task> tasks = new List<Task>();
    for (int i = 0; i < 10; i++)
    {
        var tempi = i;
        var t = Task.Run(() =>
        {
            List<int> tempData = new List<int>();
            foreach (var d in data)
            {
                tempData.Add(d);
            }
            Console.WriteLine($"i:{tempi},合計:{data.Sum()},是否相等:{data.Sum() == tempData.Sum()}");
        });
        tasks.Add(t);
    }

    await Task.WhenAll(tasks); //或者Task.WaitAll(tasks.ToArray());
    Console.WriteLine("多執行緒執行結束");
}

不同的執行緒同一段程式碼,但不會是同一作用域,所以tempData資料沒有互相影響。

全域性變數:data,多個執行緒都可以訪問,list只讀的時候是線性安全
區域性變數:i就是區域性變數,訪問的執行緒可以訪問,去掉【var tempi = i;】,執行結果打印出來,值都是一樣的,增加的都是每個執行緒都訪問單獨的tempi變數

i:10,合計:500500,是否相等:True
i:10,合計:500500,是否相等:True
i:10,合計:500500,是否相等:True
i:10,合計:500500,是否相等:True
i:10,合計:500500,是否相等:True
i:10,合計:500500,是否相等:True
i:10,合計:500500,是否相等:True
i:10,合計:500500,是否相等:True
i:10,合計:500500,是否相等:True
i:10,合計:500500,是否相等:True

執行緒變數:tempData,每個執行緒只訪問自己的,互不影響,執行結果

i:3,合計:500500,是否相等:True
i:6,合計:500500,是否相等:True
i:0,合計:500500,是否相等:True
i:1,合計:500500,是否相等:True
i:4,合計:500500,是否相等:True
i:2,合計:500500,是否相等:True
i:7,合計:500500,是否相等:True
i:5,合計:500500,是否相等:True
i:8,合計:500500,是否相等:True
i:9,合計:500500,是否相等:True

寫多執行緒的時候需要注意,變數的作用域,否則程式執行出來的結果將不會是想要的結果,注意,注意變數作用