《C#並發編程經典實例》學習筆記—3.1 數據的並行處理


問題

有一批數據,需要對每個元素進行相同的操作。該操作是計算密集型的,需要耗費一定的時間。

解決方案

常見的操作可以粗略分為 計算密集型操作 和 IO密集型操作。計算密集型操作主要是依賴於CPU計算,所以可以最大限度利用多核CPU的並行操作非常適合計算密集型操作。圖像操作是比較常見的計算密集型操作,圖像操作一般是借助矩陣存儲圖像數據,該書作者就舉了矩陣旋轉為例。
思路是借助Parallel.ForEach實現並行操作。
偽代碼如下

void RotateMatrices(IEnumerable<Matrix> matrices, float degrees)
{
    Parallel.ForEach(matrices, matrix => matrix.Rotate(degrees));
}

當前循環處理無效值時,可能需要停止該循環,實現如下

void InvertMatrices(IEnumerable<Matrix> matrices)
{
    Parallel.ForEach(matrices, (matrix, state) =>
    {
        if (!matrix.IsInvertible)
            state.Stop();
        else
            matrix.Invert();
    });
}

而如果是想要取消整個並行循環,則需要借助CancellationToken,即可以有一個取消按鈕,點擊取消按鈕,應取消循環操作。

void RotateMatrices(IEnumerable<Matrix> matrices, float degrees,
CancellationToken token)
{
    Parallel.ForEach(matrices,
    new ParallelOptions { CancellationToken = token },
    matrix => matrix.Rotate(degrees));
}

另:當一個全局變量在並行循環內部被操作時,則需要考慮多進程共享狀態。因為並行循環的每個循環很可能在不同的線程中運行。

// 注意,這不是最高效的實現方式。
// 只是舉個例子,說明用鎖來保護共享狀態。
int InvertMatrices(IEnumerable<Matrix> matrices)
{
    object mutex = new object();
    int nonInvertibleCount = 0;
    Parallel.ForEach(matrices, matrix =>
    {
        if (matrix.IsInvertible)
        {
            matrix.Invert();
        }
        else
        {
            lock (mutex)
            {
                ++nonInvertibleCount;
            }
        }
    });
    return nonInvertibleCount;
}

《C#並發編程經典實例》學習筆記-第一章並發編程概述 - repeatedly - 博客園 ,我提到了並行操作的兩種方式,一種是Parallel,另一種是PLINQ(Parallel LINQ)。所以上述操作也可以使用PLINQ實現。

兩者是有區別的,區別如下:

Parallel 類和 PLINQ 之間有一個區別:PLINQ 假設可以使用計算機內所有的CPU 核,而 Parallel 類則會根據 CPU 狀態的變化動態地調整。

相信對C#語法比較熟悉的應該能看出來,Parallel.ForEach是並行foreach循環,那么並行for循環對應的方法是什么呢?是Parallel.For 方法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM