مشاركة عبر


كيفية القيام بما يلي: كتابة تنفيذ تكرار حلقي مستمرة متوازى.For بسيط

يوضح هذا المثال كيفية إلى استخدام التحميل الزائد أبسط من Parallel.Forأسلوب إلى حساب حاصل الثاني المصفوفات. كما يوضح كيفية استخدام System.Diagnostics.Stopwatchفئة لمقارنة الأداء متوازى الحلقة بغير-متوازى تكرار حلقي.

ملاحظةملاحظة

يستخدم هذه الوثائق تعبيرات لامدا إلى تعريف التفويضات في TPL.إذا لم تكن معتاداً على تعبيرات لامدا في C# أو Visual أساسى، راجع لامدا التعبيرات في PLINQ و TPL.

مثال

' 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
    }

}

يمكنك استخدم التحميل الزائد أساسى Forالطريقة عند عدم تحتاج إلى إلغاء الأمر أو قطع من التكرار أو الاحتفاظ بأية الولاية مؤشر ترابط المحلية.

عند parallelizing أي تعليمات برمجية، متضمناً loops، واحد الهامة والهدف هو الاستفادة من المعالجات قدر الإمكان دون عبر parallelizing إلى النقطة الموقع يكون مقدار الحمل للمعالجة المتوازية negates أية مزايا الأداء. في هذا الخاصة مثال، هو parallelized الحلقة الخارجية فقط لأنه لا يوجد كثير جداً العمل المنجز في تكرار حلقي داخلية. التركيبة من مقدار مربع متوسط من العمل والتأثيرات undesirable ذاكرة تخزين مؤقتة قد يتسبب في انخفاض الأداء الأداء في المتداخلة متوازى حلقات. ولذلك، parallelizing الحلقة الخارجية فقط هو أفضل طريقة لزيادة الفوائد التي ستنجم عن التزامن تشغيل معظم الأنظمة.

تفويض

معلمة الثالث من هذا التحميل الزائد من Forهو تفويض من النوع Action<int>في C# أو Action(Of Integer)في Visual أساسى. Actionتفويض، وما إذا كان يحتوي على صفر أو واحد أو نوع sixteen معلمات دائماً إرجاع فارغ (Void). في الأساسية Vهوual، سلوك Actionهو معرفة Sub. يستخدم المثال تعبير lambda إلى إنشاء المفوض، ولكن يمكنك إنشاء المفوض بطرق غير ذلك أيضا. لمزيد من المعلومات، راجع لامدا التعبيرات في PLINQ و TPL.

"القيمة" تكرار "

يأخذ المفوض واحدة معلمة الإدخال قيمته هو تكرار الحالي. Th هو قيمة تكرار هو متوفرة بواسطة وقت التشغيل وقيمتها البداية هو فهرس العنصر أول تشغيل المقطع المصدر (قسم) التي هو التي يتم معالجتها تشغيل مسار التنفيذ الحالي.

إذا كنت تطلب المزيد من التحكم المستوى التزامن، استخدم واحد التحميلات الزائدة التي تأخذ System.Threading.Tasks.ParallelOptionsمعلمة الإدخال، مثل كـ: Parallel.For(Int32, Int32, ParallelOptions, Action<Int32, ParallelLoopState>).

الالقيمة المرجعة ومعالجة ‏‏ استثناء

ForإرجاعSystem.Threading.Tasks.ParallelLoopResultكائن عند مكتمل الجميع عمليات جزئية. Th هو القيمة الإرجاع هو مفيدة عندما يتم إيقاف تشغيل أو breaking تكرار حلقي تكرار يدوياً، لأنه ParallelLoopResultبتخزين المعلومات مثل تكرار الأخير الذي تم تشغيل للاكتمال. في حالة حدوث استثناء واحد أو أكثر تشغيل أحد عمليات جزئية، System.AggregateExceptionسوف يتم طرح.

في تعليمات برمجية في ترتيب هو سبيل المثال، القيمة الإرجاع ل Forهو غير مستخدمة.

التحليل و الأداء

يمكنك استخدام "معالج الأداء" إلى عرض استخدام CPU تشغيل جهاز الكمبيوتر الخاص بك. كـ تجربة، increكـe عدد أعمدة والصفوف في التنظيمات. كلما زادت التنظيمات، زاد الفرق الأداء بين متوازى وإصدارات متتالية احتساب. عندما المصفوفة مربع متوسط، الإصدار متسلسلة ستعمل أسرع نتيجة التحميل الزائد في إعداد التوازي تكرار حلقي.

سوف ملحوظ للاستدعاءات المتزامنة إلى موارد المشتركة، مثل وحدة تحكم أو النظام الملفات، ينخفض أداء جنبا إلى جنب تكرار حلقي. عند قياس الأداء، حاول تجنب المكالمات مثل Console.WriteLineداخل الحلقة.

التحويل البرمجي للتعليمات البرمجية

  • قص ولصق هذا الرمز في مشروع Visual Basic 2010 Studio.

راجع أيضًا:

المرجع

For

ForEach

المبادئ

بيانات متوازى ism (مكتبة متوازى المهام)

البرمجة المتوازية في .NET Framework