مشاركة عبر


كيفية القيام بما يلي: قم بإلغاء استعلام PLINQ

تبين الأمثلة التالية طريقتين إلى إلغاء استعلام PLINQ. يظهر المثال أول كيفية إلى إلغاء الأمر استعلام يتكون غالباً من اجتياز بيانات. يظهر المثال الثاني كيفية إلغاء الأمر استعلام يحتوي على مستخدم يعمل التي هو الثمن الممكن.

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

عند "فقط رمز مجلد" هو ممكناً، إلى قطع Studio Vهوual تشغيل الخط الذي يطرح ‏‏ استثناء و dهوplay رسالة خطأ تقول "لم يتم التعامل معها من قبل المستخدم رمز ‏‏ استثناء." وهذا خطأ هو benign.اضغط على F5 إلى متابعة منه، ومشاهدة سلوك معالجة الاستثناءات التي يتم هو موضح في الأمثلة أدناه.لمنع الانفصال عن الخطأ أول ‏‫Visual Studio، فقط إلغاء تحديد "فقط الخاصة بي تعليمات برمجية" خانة الاختيار تحت أدوات، خيارات، تصحيح، عام.

مثال

Class Program
    Private Shared Sub Main(ByVal args As String())
        Dim source As Integer() = Enumerable.Range(1, 10000000).ToArray()
        Dim cs As New CancellationTokenSource()

        ' Start a new asynchronous task that will cancel the 
        ' operation from another thread. Typically you would call
        ' Cancel() in response to a button click or some other
        ' user interface event.
        Task.Factory.StartNew(Sub()
                                  UserClicksTheCancelButton(cs)
                              End Sub)

        Dim results As Integer() = Nothing
        Try

            results = (From num In source.AsParallel().WithCancellation(cs.Token) _
                Where num Mod 3 = 0 _
                Order By num Descending _
                Select num).ToArray()
        Catch e As OperationCanceledException

            Console.WriteLine(e.Message)
        Catch ae As AggregateException

            If ae.InnerExceptions IsNot Nothing Then
                For Each e As Exception In ae.InnerExceptions
                    Console.WriteLine(e.Message)
                Next
            End If
        End Try

        If results IsNot Nothing Then
            For Each item In results
                Console.WriteLine(item)
            Next
        End If
        Console.WriteLine()

        Console.ReadKey()
    End Sub

    Private Shared Sub UserClicksTheCancelButton(ByVal cs As CancellationTokenSource)
        ' Wait between 150 and 500 ms, then cancel.
        ' Adjust these values if necessary to make
        ' cancellation fire while query is still executing.
        Dim rand As New Random()
        Thread.Sleep(rand.[Next](150, 350))
        cs.Cancel()
    End Sub
End Class
namespace PLINQCancellation_1
{
    using System;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;

    class Program
    {
        static void Main(string[] args)
        {
            int[] source = Enumerable.Range(1, 10000000).ToArray();
            CancellationTokenSource cs = new CancellationTokenSource();

            // Start a new asynchronous task that will cancel the 
            // operation from another thread. Typically you would call
            // Cancel() in response to a button click or some other
            // user interface event.
            Task.Factory.StartNew(() =>
            {
                UserClicksTheCancelButton(cs);
            });

            int[] results = null;
            try
            {
                results = (from num in source.AsParallel().WithCancellation(cs.Token)
                           where num % 3 == 0
                           orderby num descending
                           select num).ToArray();

            }

            catch (OperationCanceledException e)
            {
                Console.WriteLine(e.Message);
            }

            catch (AggregateException ae)
            {
                if (ae.InnerExceptions != null)
                {
                    foreach (Exception e in ae.InnerExceptions)
                        Console.WriteLine(e.Message);
                }
            }

            if (results != null)
            {
                foreach (var v in results)
                    Console.WriteLine(v);
            }
            Console.WriteLine();
            Console.ReadKey();

        }

        static void UserClicksTheCancelButton(CancellationTokenSource cs)
        {
            // Wait between 150 and 500 ms, then cancel.
            // Adjust these values if necessary to make
            // cancellation fire while query is still executing.
            Random rand = new Random();
            Thread.Sleep(rand.Next(150, 350));
            cs.Cancel();
        }
    }
}

لا إطار عمل PLINQ برمي واحدة OperationCanceledExceptionفي System.AggregateException؛ OperationCanceledExceptionيجب أن تتم معالجتها في حظر catch منفصلة. إذا كان يطرح مفوض مستخدم مفرد أو أكثر OperationCanceledException(externalCT) (باستخدام خارجية System.Threading.CancellationToken) ولكن لا يوجد غير ذلك الاستثناء، والاستعلام تم تعريفه ك AsParallel().WithCancellation(externalCT)، ثم تصدر PLINQ مفردة OperationCanceledException(externalCT) بدلاً من System.AggregateException. ومع ذلك، إذا كان تفويض مستخدم واحد يطرح OperationCanceledException، و المفوض آخر يطرح نوع ‏‏ استثناء آخر، ثم سيتم التراجع عن كل من ‏‏ استثناءات في AggregateException.

إرشادات عامة تشغيل الإلغاء هو كما يلي:

  1. إذا كنت تقوم بإلغاء التفويض بالمستخدم الذي يجب إعلام PLINQ حول خارجي CancellationTokenو الإلقاء OperationCanceledException(externalCT).

  2. في حالة حدوث الإلغاء وتكون أية استثناءات تم طرح، ثم يجب أن تقوم بمعالجة OperationCanceledExceptionبدلاً من AggregateException.

يوضح المثال التالي كيفية إلى معالجة الإلغاء عندما يكون لديك دالة الثمن الممكن في تعليمات برمجية للمستخدم.

Class Program2
    Private Shared Sub Main(ByVal args As String())


        Dim source As Integer() = Enumerable.Range(1, 10000000).ToArray()
        Dim cs As New CancellationTokenSource()

        ' Start a new asynchronous task that will cancel the 
        ' operation from another thread. Typically you would call
        ' Cancel() in response to a button click or some other
        ' user interface event.
        Task.Factory.StartNew(Sub()

                                  UserClicksTheCancelButton(cs)
                              End Sub)

        Dim results As Double() = Nothing
        Try

            results = (From num In source.AsParallel().WithCancellation(cs.Token) _
                Where num Mod 3 = 0 _
                Select [Function](num, cs.Token)).ToArray()
        Catch e As OperationCanceledException


            Console.WriteLine(e.Message)
        Catch ae As AggregateException
            If ae.InnerExceptions IsNot Nothing Then
                For Each e As Exception In ae.InnerExceptions
                    Console.WriteLine(e.Message)
                Next
            End If
        End Try

        If results IsNot Nothing Then
            For Each item In results
                Console.WriteLine(item)
            Next
        End If
        Console.WriteLine()

        Console.ReadKey()
    End Sub

    ' A toy method to simulate work.
    Private Shared Function [Function](ByVal n As Integer, ByVal ct As CancellationToken) As Double
        ' If work is expected to take longer than 1 ms
        ' then try to check cancellation status more
        ' often within that work.
        For i As Integer = 0 To 4
            ' Work hard for approx 1 millisecond.
            Thread.SpinWait(50000)

            ' Check for cancellation request.
            If ct.IsCancellationRequested Then
                Throw New OperationCanceledException(ct)
            End If
        Next
        ' Anything will do for our purposes.
        Return Math.Sqrt(n)
    End Function

    Private Shared Sub UserClicksTheCancelButton(ByVal cs As CancellationTokenSource)
        ' Wait between 150 and 500 ms, then cancel.
        ' Adjust these values if necessary to make
        ' cancellation fire while query is still executing.
        Dim rand As New Random()
        Thread.Sleep(rand.[Next](150, 350))
        Console.WriteLine("Press 'c' to cancel")
        If Console.ReadKey().KeyChar = "c"c Then
            cs.Cancel()

        End If
    End Sub
End Class
namespace PLINQCancellation_2
{
    using System;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;

    class Program
    {
        static void Main(string[] args)
        {


            int[] source = Enumerable.Range(1, 10000000).ToArray();
            CancellationTokenSource cs = new CancellationTokenSource();

            // Start a new asynchronous task that will cancel the 
            // operation from another thread. Typically you would call
            // Cancel() in response to a button click or some other
            // user interface event.
            Task.Factory.StartNew(() =>
            {
                UserClicksTheCancelButton(cs);
            });

            double[] results = null;
            try
            {
                results = (from num in source.AsParallel().WithCancellation(cs.Token)
                           where num % 3 == 0
                           select Function(num, cs.Token)).ToArray();

            }


            catch (OperationCanceledException e)
            {
                Console.WriteLine(e.Message);
            }
            catch (AggregateException ae)
            {
                if (ae.InnerExceptions != null)
                {
                    foreach (Exception e in ae.InnerExceptions)
                        Console.WriteLine(e.Message);
                }
            }

            if (results != null)
            {
                foreach (var v in results)
                    Console.WriteLine(v);
            }
            Console.WriteLine();
            Console.ReadKey();

        }

        // A toy method to simulate work.
        static double Function(int n, CancellationToken ct)
        {
            // If work is expected to take longer than 1 ms
            // then try to check cancellation status more
            // often within that work.
            for (int i = 0; i < 5; i++)
            {
                // Work hard for approx 1 millisecond.
                Thread.SpinWait(50000);

                // Check for cancellation request.
                ct.ThrowIfCancellationRequested();
            }
            // Anything will do for our purposes.
            return Math.Sqrt(n);
        }

        static void UserClicksTheCancelButton(CancellationTokenSource cs)
        {
            // Wait between 150 and 500 ms, then cancel.
            // Adjust these values if necessary to make
            // cancellation fire while query is still executing.
            Random rand = new Random();
            Thread.Sleep(rand.Next(150, 350));
            Console.WriteLine("Press 'c' to cancel");
            if (Console.ReadKey().KeyChar == 'c')
                cs.Cancel();
        }
    }
}

عندما تقوم بمعالجة الإلغاء في تعليمات برمجية للمستخدم، لم يكن إلى استخدام WithCancellation في تعريف الاستعلام. على الرغم من ذلك، نوصي أن تقوم بذلك لأن WithCancellation لا يؤثر على أداء الاستعلام وتمكن الإلغاء أن يتم التعامل معها من قبل مستخدم الخاص بك وعوامل تشغيل الاستعلام تعليمات برمجية.

لضمان استجابة النظام، نوصي أن تتحقق للإلغاء حول مرة واحدة كل millهوecond؛ ومع ذلك، لأي فترة إلى 10 millهوeconds هو يعتبر مقبولاً. لا ينبغي تكرار هذا تأثير سلبي تشغيل أداء تعليمات برمجية's الخاص بك.

عندما يتم التخلص من العداد، على سبيل المثال عندما يقطع التعليمات البرمجية من تكرار حلقي foreach التي هي بالتكرار عبر الاستعلام النتائج، ثم تم إلغاء الاستعلام، ولكن لا الاستثناء تم طرح.

راجع أيضًا:

المبادئ

متوازى LINQ (PLINQ)

موارد أخرى

Cancellation