Sdílet prostřednictvím


Postupy: Psát jednoduché smyčky Parallel.For

Tento příklad ukazuje použití nejjednodušší přetížení Parallel.For Metoda výpočtu součin dvou matic. Také zobrazuje způsob použití System.Diagnostics.Stopwatch třídy porovnání výkonu paralelní smyčka loop-paralelní.

PoznámkaPoznámka

Tato dokumentace používá k definování delegátů v TPL lambda výrazy.Pokud nejste obeznámeni s lambda výrazy v jazyce C# nebo Visual Basic, pokračujte na Lambda výrazy v PLINQ a TPL.

Příklad

' How to: Write a Simple Parallel.For Loop 
Imports System.Threading.Tasks
Module MultiplyMatrices

#Region "Sequential_Loop"
    Sub MultiplyMatricesSequential(ByVal matA As Double(,), ByVal matB As Double(,), ByVal result As Double(,))
        Dim matACols As Integer = matA.GetLength(1)
        Dim matBCols As Integer = matB.GetLength(1)
        Dim matARows As Integer = matA.GetLength(0)

        For i As Integer = 0 To matARows - 1
            For j As Integer = 0 To matBCols - 1
                For k As Integer = 0 To matACols - 1
                    result(i, j) += matA(i, k) * matB(k, j)
                Next
            Next
        Next
    End Sub
#End Region

#Region "Parallel_Loop"

    Private Sub MultiplyMatricesParallel(ByVal matA As Double(,), ByVal matB As Double(,), ByVal result As Double(,))
        Dim matACols As Integer = matA.GetLength(1)
        Dim matBCols As Integer = matB.GetLength(1)
        Dim matARows As Integer = matA.GetLength(0)

        ' A basic matrix multiplication.
        ' Parallelize the outer loop to partition the source array by rows.
        Parallel.For(0, matARows, Sub(i)
                                      For j As Integer = 0 To matBCols - 1
                                          ' Use a temporary to improve parallel performance.
                                          Dim temp As Double = 0
                                          For k As Integer = 0 To matACols - 1
                                              temp += matA(i, k) * matB(k, j)
                                          Next
                                          result(i, j) += temp
                                      Next
                                  End Sub)
    End Sub
#End Region


#Region "Main"
    Sub Main(ByVal args As String())
        ' Set up matrices. Use small values to better view 
        ' result matrix. Increase the counts to see greater 
        ' speedup in the parallel loop vs. the sequential loop.
        Dim colCount As Integer = 180
        Dim rowCount As Integer = 2000
        Dim colCount2 As Integer = 270
        Dim m1 As Double(,) = InitializeMatrix(rowCount, colCount)
        Dim m2 As Double(,) = InitializeMatrix(colCount, colCount2)
        Dim result As Double(,) = New Double(rowCount - 1, colCount2 - 1) {}

        ' First do the sequential version.
        Console.WriteLine("Executing sequential loop...")
        Dim stopwatch As New Stopwatch()
        stopwatch.Start()

        MultiplyMatricesSequential(m1, m2, result)
        stopwatch.[Stop]()
        Console.WriteLine("Sequential loop time in milliseconds: {0}", stopwatch.ElapsedMilliseconds)

        ' For the skeptics.
        OfferToPrint(rowCount, colCount2, result)

        ' Reset timer and results matrix. 
        stopwatch.Reset()
        result = New Double(rowCount - 1, colCount2 - 1) {}

        ' Do the parallel loop.
        Console.WriteLine("Executing parallel loop...")
        stopwatch.Start()
        MultiplyMatricesParallel(m1, m2, result)
        stopwatch.[Stop]()
        Console.WriteLine("Parallel loop time in milliseconds: {0}", stopwatch.ElapsedMilliseconds)
        OfferToPrint(rowCount, colCount2, result)

        ' Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.")
        Console.ReadKey()
    End Sub
#End Region

#Region "Helper_Methods"

    Function InitializeMatrix(ByVal rows As Integer, ByVal cols As Integer) As Double(,)
        Dim matrix As Double(,) = New Double(rows - 1, cols - 1) {}

        Dim r As New Random()
        For i As Integer = 0 To rows - 1
            For j As Integer = 0 To cols - 1
                matrix(i, j) = r.[Next](100)
            Next
        Next
        Return matrix
    End Function

    Sub OfferToPrint(ByVal rowCount As Integer, ByVal colCount As Integer, ByVal matrix As Double(,))
        Console.WriteLine("Computation complete. Print results? y/n")
        Dim c As Char = Console.ReadKey().KeyChar
        If c = "y"c OrElse c = "Y"c Then
            Console.WindowWidth = 168
            Console.WriteLine()
            For x As Integer = 0 To rowCount - 1
                Console.WriteLine("ROW {0}: ", x)
                For y As Integer = 0 To colCount - 1
                    Console.Write("{0:#.##} ", matrix(x, y))
                Next
                Console.WriteLine()
            Next
        End If
    End Sub

#End Region
End Module
namespace MultiplyMatrices
{
    using System;
    using System.Collections.Generic;
    using System.Collections.Concurrent;
    using System.Diagnostics;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;

    class Program
    {
        #region Sequential_Loop
        static void MultiplyMatricesSequential(double[,] matA, double[,] matB,
                                                double[,] result)
        {
            int matACols = matA.GetLength(1);
            int matBCols = matB.GetLength(1);
            int matARows = matA.GetLength(0);

            for (int i = 0; i < matARows; i++)
            {
                for (int j = 0; j < matBCols; j++)
                {
                    for (int k = 0; k < matACols; k++)
                    {
                        result[i, j] += matA[i, k] * matB[k, j];
                    }
                }
            }
        }
        #endregion

        #region Parallel_Loop

        static void MultiplyMatricesParallel(double[,] matA, double[,] matB, double[,] result)
        {
            int matACols = matA.GetLength(1);
            int matBCols = matB.GetLength(1);
            int matARows = matA.GetLength(0);

            // A basic matrix multiplication.
            // Parallelize the outer loop to partition the source array by rows.
            Parallel.For(0, matARows, i =>
            {
                for (int j = 0; j < matBCols; j++)
                {
                    // Use a temporary to improve parallel performance.
                    double temp = 0;
                    for (int k = 0; k < matACols; k++)
                    {
                        temp += matA[i, k] * matB[k, j];
                    }
                    result[i, j] = temp;
                }
            }); // Parallel.For
        }

        #endregion


        #region Main
        static void Main(string[] args)
        {
            // Set up matrices. Use small values to better view 
            // result matrix. Increase the counts to see greater 
            // speedup in the parallel loop vs. the sequential loop.
            int colCount = 180;
            int rowCount = 2000;
            int colCount2 = 270;
            double[,] m1 = InitializeMatrix(rowCount, colCount);
            double[,] m2 = InitializeMatrix(colCount, colCount2);
            double[,] result = new double[rowCount, colCount2];

            // First do the sequential version.
            Console.WriteLine("Executing sequential loop...");
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();

            MultiplyMatricesSequential(m1, m2, result);
            stopwatch.Stop();
            Console.WriteLine("Sequential loop time in milliseconds: {0}", stopwatch.ElapsedMilliseconds);

            // For the skeptics.
            OfferToPrint(rowCount, colCount2, result);

            // Reset timer and results matrix. 
            stopwatch.Reset();
            result = new double[rowCount, colCount2];

            // Do the parallel loop.
            Console.WriteLine("Executing parallel loop...");
            stopwatch.Start();
            MultiplyMatricesParallel(m1, m2, result);
            stopwatch.Stop();
            Console.WriteLine("Parallel loop time in milliseconds: {0}", stopwatch.ElapsedMilliseconds);
            OfferToPrint(rowCount, colCount2, result);

            // Keep the console window open in debug mode.
            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }


        #endregion

        #region Helper_Methods

        static double[,] InitializeMatrix(int rows, int cols)
        {
            double[,] matrix = new double[rows, cols];

            Random r = new Random();
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    matrix[i, j] = r.Next(100);
                }
            }
            return matrix;
        }

        private static void OfferToPrint(int rowCount, int colCount, double[,] matrix)
        {
            Console.WriteLine("Computation complete. Print results? y/n");
            char c = Console.ReadKey().KeyChar;
            if (c == 'y' || c == 'Y')
            {
                Console.WindowWidth = 180;
                Console.WriteLine();
                for (int x = 0; x < rowCount; x++)
                {
                    Console.WriteLine("ROW {0}: ", x);
                    for (int y = 0; y < colCount; y++)
                    {
                        Console.Write("{0:#.##} ", matrix[x, y]);
                    }
                    Console.WriteLine();
                }

            }
        }

        #endregion
    }

}

Můžete použít základní přetížení For Metoda při nutné zrušit nebo přerušit iterací nebo zachovat všechny místní podproces státu.

Při parallelizing žádný kód, včetně smyčky, jeden důležitý cíl je využívat co nejvíce bez procesorů nad parallelizing bod, kde režii paralelní zpracování Neguje výhody výkonu. Zejména například Vnější smyčka je parallelized, protože není velmi mnoho práce prováděny vnitřní smyčku. Kombinaci malé množství práce a mezipaměti nežádoucí účinky mohou způsobit snížení výkonu ve vnořených paralelní smyčky. Parallelizing Vnější smyčka pouze tedy nejlépe maximalizovat výhody souběžnosti ve většině systémů.

Delegát

Třetí parametr toto přetížení For je typ delegáta Action<int> v jazyce C# nebo Action(Of Integer) v jazyce Visual Basic. Action Delegovat, zda má nula, jedna nebo šestnáct zadání parametrů vždy vrátí void. V jazyce Visual Basic chování Action je definován s Sub. V příkladu lambda výraz vytvořit delegát, ale delegátovi můžete vytvořit také jinými způsoby. Další informace naleznete v tématu Lambda výrazy v PLINQ a TPL.

Hodnota iterace

Delegát má jeden vstupní parametr, jehož hodnotou je aktuální iterace. Tato hodnota iterace dodává modulu runtime a je počáteční hodnota indexu prvního prvku zdroje, který je zpracováván aktuální podproces segmentu (oddílu).

Pokud požadujete větší kontrolu nad úroveň souběžnosti, použijte jednu z přetížení, které trvá System.Threading.Tasks.ParallelOptions Vstupní parametr, například: Parallel.For(Int32, Int32, ParallelOptions, Action<Int32, ParallelLoopState>).

Vrácená hodnota a zpracování výjimek

ForVrátí System.Threading.Tasks.ParallelLoopResult objektu po dokončení všech podprocesů. Tento vrátí hodnotu je užitečné při zastavení nebo rozdělení iteraci smyčky ručně, protože ParallelLoopResult informacemi jako poslední iterace, která proběhla na dokončení. Pokud jeden nebo více výjimek na jednom podprocesů, System.AggregateException bude vyvolána.

V kódu v tomto příkladu vrátí hodnotu, která For se používá.

Analýza a výkon

Průvodce výkonu můžete zobrazit využití procesoru v počítači. Jako experimentu zvýšíte počet sloupců a řádků v matricí. Větší matice, tím větší výkon rozdíl mezi paralelní a sekvenční verze výpočtu. Když matice je malá, sekvenční verze bude z důvodu zatížení v nastavení paralelního smyčky pracovat rychleji.

Synchronní volání ke sdíleným prostředkům systému souborů nebo konzoly bude výrazně snížit výkon paralelní smyčky. Při měření výkonu snažte vyhnout volání jako Console.WriteLine ve smyčce.

Probíhá kompilace kódu

  • Vyjmout a vložit tento kód do projektu Visual Studio 2010.

Viz také

Odkaz

For

ForEach

Koncepty

Datový paralelismus (Task Parallel Library)

Paralelní programování v rozhraní .NET Framework