Share via


Nasıl yapılır: Olay Tabanlı Zaman Uyumsuz Deseni Destekleyen Bir Bileşeni Uygulama

Fark edilebilir gecikmelere neden olabilecek bazı işlemleri olan bir sınıf yazıyorsanız, Olay Tabanlı Zaman Uyumsuz Desene Genel Bakış'ı uygulayarak zaman uyumsuz işlevsellik vermeyi göz önünde bulundurun.

Bu kılavuzda, Olay Tabanlı Zaman Uyumsuz Deseni uygulayan bir bileşenin nasıl oluşturulacağı gösterilmektedir. Bileşenin ASP.NET, Konsol uygulamaları ve Windows Forms uygulamaları dahil olmak üzere herhangi bir uygulama modeli altında düzgün çalışmasını sağlayan ad alanından yardımcı sınıflar System.ComponentModel kullanılarak uygulanır. Bu bileşen, bir PropertyGrid denetim ve kendi özel tasarımcılarınız ile de tasarlanabilir.

İşlemi tamamladığınızda, asal sayıları zaman uyumsuz olarak hesaplayan bir uygulamanız olur. Uygulamanızın bir ana kullanıcı arabirimi (UI) iş parçacığı ve her asal sayı hesaplaması için bir iş parçacığı olacaktır. Büyük bir sayının asal olup olmadığının test edilmesi dikkate değer bir süre alabilir, ancak ana kullanıcı arabirimi iş parçacığı bu gecikmeden kesintiye uğramaz ve hesaplamalar sırasında form yanıt verir. İstediğiniz sayıda hesaplamayı eşzamanlı olarak çalıştırabilir ve bekleyen hesaplamaları seçmeli olarak iptal edebilirsiniz.

Bu kılavuzda gösterilen görevler şunlardır:

  • Bileşen Oluşturma

  • Genel Zaman Uyumsuz Olayları ve Temsilcileri Tanımlama

  • Özel Temsilci Tanımlama

  • Genel Olayları Uygulama

  • Tamamlama Yöntemini Uygulama

  • Çalışan Yöntemlerini Uygulama

  • Başlangıç ve İptal Yöntemlerini Uygulama

Bu konudaki kodu tek bir liste olarak kopyalamak için bkz . Nasıl yapılır: Olay Tabanlı Zaman Uyumsuz Desenin İstemcisini Uygulama.

Bileşen Oluşturma

İlk adım, Olay Tabanlı Zaman Uyumsuz Deseni uygulayacak bileşeni oluşturmaktır.

Bileşeni oluşturmak için

  • öğesinden Componentdevralan adlı PrimeNumberCalculator bir sınıf oluşturun.

Genel Zaman Uyumsuz Olayları ve Temsilcileri Tanımlama

Bileşeniniz olayları kullanarak istemcilerle iletişim kurar. MethodNameTamamlandı olayı istemcileri zaman uyumsuz bir görevin tamamlanması konusunda uyarır ve MethodNameProgressChanged olayı istemcileri zaman uyumsuz bir görevin ilerleme durumunu bildirir.

Bileşeninizin istemcileri için zaman uyumsuz olaylar tanımlamak için:

  1. System.Threading Dosyanızın üst kısmındaki ve System.Collections.Specialized ad alanlarını içeri aktarın.

    using System;
    using System.Collections;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Globalization;
    using System.Threading;
    using System.Windows.Forms;
    
    Imports System.Collections
    Imports System.Collections.Specialized
    Imports System.ComponentModel
    Imports System.Drawing
    Imports System.Globalization
    Imports System.Threading
    Imports System.Windows.Forms
    
  2. Sınıf tanımından PrimeNumberCalculator önce ilerleme ve tamamlama olayları için temsilciler bildirin.

    public delegate void ProgressChangedEventHandler(
        ProgressChangedEventArgs e);
    
    public delegate void CalculatePrimeCompletedEventHandler(
        object sender,
        CalculatePrimeCompletedEventArgs e);
    
    Public Delegate Sub ProgressChangedEventHandler( _
        ByVal e As ProgressChangedEventArgs)
    
    Public Delegate Sub CalculatePrimeCompletedEventHandler( _
        ByVal sender As Object, _
        ByVal e As CalculatePrimeCompletedEventArgs)
    
  3. Sınıf tanımında PrimeNumberCalculator , ilerleme durumunu ve tamamlanma durumunu istemcilere bildirmek için olayları bildirin.

    public event ProgressChangedEventHandler ProgressChanged;
    public event CalculatePrimeCompletedEventHandler CalculatePrimeCompleted;
    
    Public Event ProgressChanged _
        As ProgressChangedEventHandler
    Public Event CalculatePrimeCompleted _
        As CalculatePrimeCompletedEventHandler
    
  4. Sınıf tanımından PrimeNumberCalculator sonra, her hesaplamanın CalculatePrimeCompletedEventArgs sonucunu .event için istemcinin olay işleyicisine raporlamak için sınıfını türetin CalculatePrimeCompleted. Özelliklere AsyncCompletedEventArgs ek olarak, bu sınıf istemcinin test edilen sayıyı, asal olup olmadığını ve ilk bölenin asal değilse ne olduğunu belirlemesini sağlar.

    public class CalculatePrimeCompletedEventArgs :
        AsyncCompletedEventArgs
    {
        private int numberToTestValue = 0;
        private int firstDivisorValue = 1;
        private bool isPrimeValue;
    
        public CalculatePrimeCompletedEventArgs(
            int numberToTest,
            int firstDivisor,
            bool isPrime,
            Exception e,
            bool canceled,
            object state) : base(e, canceled, state)
        {
            this.numberToTestValue = numberToTest;
            this.firstDivisorValue = firstDivisor;
            this.isPrimeValue = isPrime;
        }
    
        public int NumberToTest
        {
            get
            {
                // Raise an exception if the operation failed or
                // was canceled.
                RaiseExceptionIfNecessary();
    
                // If the operation was successful, return the
                // property value.
                return numberToTestValue;
            }
        }
    
        public int FirstDivisor
        {
            get
            {
                // Raise an exception if the operation failed or
                // was canceled.
                RaiseExceptionIfNecessary();
    
                // If the operation was successful, return the
                // property value.
                return firstDivisorValue;
            }
        }
    
        public bool IsPrime
        {
            get
            {
                // Raise an exception if the operation failed or
                // was canceled.
                RaiseExceptionIfNecessary();
    
                // If the operation was successful, return the
                // property value.
                return isPrimeValue;
            }
        }
    }
    
    
    Public Class CalculatePrimeCompletedEventArgs
        Inherits AsyncCompletedEventArgs
        Private numberToTestValue As Integer = 0
        Private firstDivisorValue As Integer = 1
        Private isPrimeValue As Boolean
    
    
        Public Sub New( _
        ByVal numberToTest As Integer, _
        ByVal firstDivisor As Integer, _
        ByVal isPrime As Boolean, _
        ByVal e As Exception, _
        ByVal canceled As Boolean, _
        ByVal state As Object)
    
            MyBase.New(e, canceled, state)
            Me.numberToTestValue = numberToTest
            Me.firstDivisorValue = firstDivisor
            Me.isPrimeValue = isPrime
    
        End Sub
    
    
        Public ReadOnly Property NumberToTest() As Integer
            Get
                ' Raise an exception if the operation failed 
                ' or was canceled.
                RaiseExceptionIfNecessary()
    
                ' If the operation was successful, return 
                ' the property value.
                Return numberToTestValue
            End Get
        End Property
    
    
        Public ReadOnly Property FirstDivisor() As Integer
            Get
                ' Raise an exception if the operation failed 
                ' or was canceled.
                RaiseExceptionIfNecessary()
    
                ' If the operation was successful, return 
                ' the property value.
                Return firstDivisorValue
            End Get
        End Property
    
    
        Public ReadOnly Property IsPrime() As Boolean
            Get
                ' Raise an exception if the operation failed 
                ' or was canceled.
                RaiseExceptionIfNecessary()
    
                ' If the operation was successful, return 
                ' the property value.
                Return isPrimeValue
            End Get
        End Property
    End Class
    

Denetim Noktası 1

Bu noktada, bileşeni oluşturabilirsiniz.

Bileşeninizi test etmek için

  • Bileşeni derleyin.

    İki derleyici uyarısı alırsınız:

    warning CS0067: The event 'AsynchronousPatternExample.PrimeNumberCalculator.ProgressChanged' is never used  
    warning CS0067: The event 'AsynchronousPatternExample.PrimeNumberCalculator.CalculatePrimeCompleted' is never used  
    

    Bu uyarılar sonraki bölümde temizlenecektir.

Özel Temsilci Tanımlama

Bileşenin zaman uyumsuz yönleri PrimeNumberCalculator , olarak SendOrPostCallbackbilinen özel bir temsilciyle dahili olarak uygulanır. , SendOrPostCallback bir iş parçacığında yürütülen bir ThreadPool geri çağırma yöntemini temsil eder. Geri çağırma yöntemi, türünde Objecttek bir parametre alan bir imzaya sahip olmalıdır; başka bir deyişle, sarmalayıcı sınıfındaki temsilciler arasında durum geçirmeniz gerekir. Daha fazla bilgi için bkz. SendOrPostCallback.

Bileşeninizin iç zaman uyumsuz davranışını uygulamak için:

  1. sınıfında temsilcileri PrimeNumberCalculator bildirin ve oluşturunSendOrPostCallback. SendOrPostCallback adlı InitializeDelegatesbir yardımcı program yönteminde nesneleri oluşturun.

    biri istemciye ilerleme durumunu raporlamak, diğeri de istemciye tamamlanma durumunu bildirmek için olmak üzere iki temsilciye ihtiyacınız olacaktır.

    private SendOrPostCallback onProgressReportDelegate;
    private SendOrPostCallback onCompletedDelegate;
    
    Private onProgressReportDelegate As SendOrPostCallback
    Private onCompletedDelegate As SendOrPostCallback
    
    protected virtual void InitializeDelegates()
    {
        onProgressReportDelegate =
            new SendOrPostCallback(ReportProgress);
        onCompletedDelegate =
            new SendOrPostCallback(CalculateCompleted);
    }
    
    Protected Overridable Sub InitializeDelegates()
        onProgressReportDelegate = _
            New SendOrPostCallback(AddressOf ReportProgress)
        onCompletedDelegate = _
            New SendOrPostCallback(AddressOf CalculateCompleted)
    End Sub
    
  2. InitializeDelegates Bileşeninizin oluşturucusunda yöntemini çağırın.

    public PrimeNumberCalculator()
    {
        InitializeComponent();
    
        InitializeDelegates();
    }
    
    Public Sub New()
    
        InitializeComponent()
    
        InitializeDelegates()
    
    End Sub
    
  3. Sınıfında zaman uyumsuz olarak yapılacak fiili işi işleyen bir temsilci PrimeNumberCalculator bildirin. Bu temsilci, bir say ın asal olup olmadığını test eden çalışan yöntemini sarmalar. Temsilci, zaman uyumsuz işlemin ömrünü izlemek için kullanılacak bir AsyncOperation parametre alır.

    private delegate void WorkerEventHandler(
        int numberToCheck,
        AsyncOperation asyncOp);
    
    Private Delegate Sub WorkerEventHandler( _
    ByVal numberToCheck As Integer, _
    ByVal asyncOp As AsyncOperation)
    
  4. Bekleyen zaman uyumsuz işlemlerin yaşam sürelerini yönetmek için bir koleksiyon oluşturun. İstemci yürütülür ve tamamlanırken işlemleri izlemek için bir yönteme ihtiyaç duyar ve bu izleme, istemci zaman uyumsuz yönteme çağrı yaptığında istemcinin benzersiz bir belirteç veya görev kimliği geçirmesi gerektirerek yapılır. Bileşen, PrimeNumberCalculator görev kimliğini ilgili çağrısıyla ilişkilendirerek her çağrıyı izlemelidir. İstemci benzersiz olmayan bir görev kimliği geçirirse, PrimeNumberCalculator bileşen bir özel durum oluşturmalıdır.

    Bileşen, PrimeNumberCalculator adlı HybridDictionaryözel bir koleksiyon sınıfını kullanarak görev kimliğini izler. Sınıf tanımında adlı userStateToLifetimebir HybridDictionary oluşturun.

    private HybridDictionary userStateToLifetime =
        new HybridDictionary();
    
    Private userStateToLifetime As New HybridDictionary()
    

Genel Olayları Uygulama

Olay Tabanlı Zaman Uyumsuz Deseni uygulayan bileşenler, olayları kullanarak istemcilerle iletişim kurar. Bu olaylar sınıfının yardımıyla uygun iş parçacığında çağrılır AsyncOperation .

Bileşeninizin istemcilerine olay göndermek için:

  1. İstemcilere raporlama için genel olayları uygulama. İlerleme durumunu raporlamak için bir olaya ve tamamlandı bildirimi için bir olaya ihtiyacınız olacaktır.

    // This method is invoked via the AsyncOperation object,
    // so it is guaranteed to be executed on the correct thread.
    private void CalculateCompleted(object operationState)
    {
        CalculatePrimeCompletedEventArgs e =
            operationState as CalculatePrimeCompletedEventArgs;
    
        OnCalculatePrimeCompleted(e);
    }
    
    // This method is invoked via the AsyncOperation object,
    // so it is guaranteed to be executed on the correct thread.
    private void ReportProgress(object state)
    {
        ProgressChangedEventArgs e =
            state as ProgressChangedEventArgs;
    
        OnProgressChanged(e);
    }
    
    protected void OnCalculatePrimeCompleted(
        CalculatePrimeCompletedEventArgs e)
    {
        if (CalculatePrimeCompleted != null)
        {
            CalculatePrimeCompleted(this, e);
        }
    }
    
    protected void OnProgressChanged(ProgressChangedEventArgs e)
    {
        if (ProgressChanged != null)
        {
            ProgressChanged(e);
        }
    }
    
    ' This method is invoked via the AsyncOperation object,
    ' so it is guaranteed to be executed on the correct thread.
    Private Sub CalculateCompleted(ByVal operationState As Object)
        Dim e As CalculatePrimeCompletedEventArgs = operationState
    
        OnCalculatePrimeCompleted(e)
    
    End Sub
    
    
    ' This method is invoked via the AsyncOperation object,
    ' so it is guaranteed to be executed on the correct thread.
    Private Sub ReportProgress(ByVal state As Object)
        Dim e As ProgressChangedEventArgs = state
    
        OnProgressChanged(e)
    
    End Sub
    
    Protected Sub OnCalculatePrimeCompleted( _
        ByVal e As CalculatePrimeCompletedEventArgs)
    
        RaiseEvent CalculatePrimeCompleted(Me, e)
    
    End Sub
    
    
    Protected Sub OnProgressChanged( _
        ByVal e As ProgressChangedEventArgs)
    
        RaiseEvent ProgressChanged(e)
    
    End Sub
    

Tamamlama Yöntemini Uygulama

Tamamlama temsilcisi, zaman uyumsuz işlem başarıyla tamamlanarak, hatayla veya iptalle sona erdiğinde temel alınan, serbest iş parçacıklı zaman uyumsuz davranışın çağıracağı yöntemdir. Bu çağrı rastgele bir iş parçacığında gerçekleşir.

Bu yöntem, istemcinin görev kimliğinin benzersiz istemci belirteçlerinin iç koleksiyonundan kaldırıldığı yöntemdir. Bu yöntem, ilgili AsyncOperationüzerinde yöntemini çağırarak PostOperationCompleted belirli bir zaman uyumsuz işlemin ömrünü de sonlandırır. Bu çağrı, uygulama modeli için uygun olan iş parçacığında tamamlama olayını oluşturur. PostOperationCompleted yöntemi çağrıldıktan sonra, bu örneği AsyncOperation artık kullanılamaz ve sonraki kullanım girişimleri bir özel durum oluşturur.

İmza, CompletionMethod zaman uyumsuz işlemin sonucunu açıklamak için gereken tüm durumu tutmalıdır. Bu belirli zaman uyumsuz işlem tarafından test edilen sayının durumunu, sayının asal olup olmadığını ve asal sayı değilse ilk bölenin değerini tutar. Ayrıca, oluşan özel durumları ve bu göreve karşılık gelen durumu AsyncOperation da açıklar.

Zaman uyumsuz bir işlemi tamamlamak için:

  • Tamamlama yöntemini uygulayın. İstemcinin aracılığıyla CalculatePrimeCompletedEventHandleristemciye döndürülen öğesini CalculatePrimeCompletedEventArgs doldurmak için kullandığı altı parametreyi alır. İstemcinin görev kimliği belirtecini iç koleksiyondan kaldırır ve zaman uyumsuz işlemin ömrünü çağrısıyla PostOperationCompletedsonlandırır. , AsyncOperation uygulama modeli için uygun olan iş parçacığına veya bağlama çağrısını sıralar.

    // This is the method that the underlying, free-threaded
    // asynchronous behavior will invoke.  This will happen on
    // an arbitrary thread.
    private void CompletionMethod(
        int numberToTest,
        int firstDivisor,
        bool isPrime,
        Exception exception,
        bool canceled,
        AsyncOperation asyncOp )
    
    {
        // If the task was not previously canceled,
        // remove the task from the lifetime collection.
        if (!canceled)
        {
            lock (userStateToLifetime.SyncRoot)
            {
                userStateToLifetime.Remove(asyncOp.UserSuppliedState);
            }
        }
    
        // Package the results of the operation in a
        // CalculatePrimeCompletedEventArgs.
        CalculatePrimeCompletedEventArgs e =
            new CalculatePrimeCompletedEventArgs(
            numberToTest,
            firstDivisor,
            isPrime,
            exception,
            canceled,
            asyncOp.UserSuppliedState);
    
        // End the task. The asyncOp object is responsible
        // for marshaling the call.
        asyncOp.PostOperationCompleted(onCompletedDelegate, e);
    
        // Note that after the call to OperationCompleted,
        // asyncOp is no longer usable, and any attempt to use it
        // will cause an exception to be thrown.
    }
    
    ' This is the method that the underlying, free-threaded 
    ' asynchronous behavior will invoke.  This will happen on
    '  an arbitrary thread.
    Private Sub CompletionMethod( _
        ByVal numberToTest As Integer, _
        ByVal firstDivisor As Integer, _
        ByVal prime As Boolean, _
        ByVal exc As Exception, _
        ByVal canceled As Boolean, _
        ByVal asyncOp As AsyncOperation)
    
        ' If the task was not previously canceled,
        ' remove the task from the lifetime collection.
        If Not canceled Then
            SyncLock userStateToLifetime.SyncRoot
                userStateToLifetime.Remove(asyncOp.UserSuppliedState)
            End SyncLock
        End If
    
        ' Package the results of the operation in a 
        ' CalculatePrimeCompletedEventArgs.
        Dim e As New CalculatePrimeCompletedEventArgs( _
            numberToTest, _
            firstDivisor, _
            prime, _
            exc, _
            canceled, _
            asyncOp.UserSuppliedState)
    
        ' End the task. The asyncOp object is responsible 
        ' for marshaling the call.
        asyncOp.PostOperationCompleted(onCompletedDelegate, e)
    
        ' Note that after the call to PostOperationCompleted, asyncOp
        ' is no longer usable, and any attempt to use it will cause.
        ' an exception to be thrown.
    
    End Sub
    

Denetim Noktası 2

Bu noktada, bileşeni oluşturabilirsiniz.

Bileşeninizi test etmek için

  • Bileşeni derleyin.

    Bir derleyici uyarısı alırsınız:

    warning CS0169: The private field 'AsynchronousPatternExample.PrimeNumberCalculator.workerDelegate' is never used  
    

    Bu uyarı sonraki bölümde çözülecektir.

Çalışan Yöntemlerini Uygulama

Şimdiye kadar bileşen için PrimeNumberCalculator zaman uyumsuz kodu desteklediniz. Artık gerçek işi gerçekleştiren kodu uygulayabilirsiniz. Üç yöntem uygulayacaksınız: CalculateWorker, BuildPrimeNumberListve IsPrime. Birlikte ve BuildPrimeNumberListIsPrime Eratosthenes'in Sieve'i olarak bilinen bir algoritmadan oluşur. Bu algoritma, test numarasının karekökünü oluşturan tüm asal sayıları bularak bir sayının asal olup olmadığını belirler. Bu noktaya kadar hiçbir bölen bulunamazsa, test numarası asal olur.

Bu bileşen maksimum verimlilik için yazılmışsa, farklı test numaraları için çeşitli çağrılar tarafından bulunan tüm asal sayıları hatırlayacaktır. Ayrıca 2, 3 ve 5 gibi önemsiz bölenleri de denetler. Bu örneğin amacı, zaman alan işlemlerin zaman uyumsuz olarak nasıl yürütülebileceğini göstermektir, ancak bu iyileştirmeler sizin için bir alıştırma olarak bırakılır.

CalculateWorker yöntemi bir temsilciye sarmalanır ve çağrısıyla BeginInvokezaman uyumsuz olarak çağrılır.

Not

İlerleme raporlama yönteminde BuildPrimeNumberList uygulanır. Hızlı bilgisayarlarda olaylar ProgressChanged hızla art arda tetiklenebilir. Bu olayların oluşturulduğu istemci iş parçacığının bu durumu işleyebilmesi gerekir. Kullanıcı arabirimi kodu iletilerle dolup yetişemeyebilir ve yanıt vermemeye neden olabilir. Bu durumu işleyen örnek bir kullanıcı arabirimi için bkz . Nasıl yapılır: Olay Tabanlı Zaman Uyumsuz Desenin İstemcisini Uygulama.

Asal sayı hesaplamasını zaman uyumsuz olarak yürütmek için:

  1. TaskCanceled Yardımcı program yöntemini uygulayın. Bu, verilen görev kimliği için görev ömrü koleksiyonunu denetler ve görev kimliği bulunamazsa döndürür true .

    // Utility method for determining if a
    // task has been canceled.
    private bool TaskCanceled(object taskId)
    {
        return( userStateToLifetime[taskId] == null );
    }
    
    ' Utility method for determining if a 
    ' task has been canceled.
    Private Function TaskCanceled(ByVal taskId As Object) As Boolean
        Return (userStateToLifetime(taskId) Is Nothing)
    End Function
    
  2. CalculateWorker yöntemini uygulayın. İki parametre alır: test etmek için bir sayı ve bir AsyncOperation.

    // This method performs the actual prime number computation.
    // It is executed on the worker thread.
    private void CalculateWorker(
        int numberToTest,
        AsyncOperation asyncOp)
    {
        bool isPrime = false;
        int firstDivisor = 1;
        Exception e = null;
    
        // Check that the task is still active.
        // The operation may have been canceled before
        // the thread was scheduled.
        if (!TaskCanceled(asyncOp.UserSuppliedState))
        {
            try
            {
                // Find all the prime numbers up to
                // the square root of numberToTest.
                ArrayList primes = BuildPrimeNumberList(
                    numberToTest,
                    asyncOp);
    
                // Now we have a list of primes less than
                // numberToTest.
                isPrime = IsPrime(
                    primes,
                    numberToTest,
                    out firstDivisor);
            }
            catch (Exception ex)
            {
                e = ex;
            }
        }
    
        //CalculatePrimeState calcState = new CalculatePrimeState(
        //        numberToTest,
        //        firstDivisor,
        //        isPrime,
        //        e,
        //        TaskCanceled(asyncOp.UserSuppliedState),
        //        asyncOp);
    
        //this.CompletionMethod(calcState);
    
        this.CompletionMethod(
            numberToTest,
            firstDivisor,
            isPrime,
            e,
            TaskCanceled(asyncOp.UserSuppliedState),
            asyncOp);
    
        //completionMethodDelegate(calcState);
    }
    
    ' This method performs the actual prime number computation.
    ' It is executed on the worker thread.
    Private Sub CalculateWorker( _
        ByVal numberToTest As Integer, _
        ByVal asyncOp As AsyncOperation)
    
        Dim prime As Boolean = False
        Dim firstDivisor As Integer = 1
        Dim exc As Exception = Nothing
    
        ' Check that the task is still active.
        ' The operation may have been canceled before
        ' the thread was scheduled.
        If Not Me.TaskCanceled(asyncOp.UserSuppliedState) Then
    
            Try
                ' Find all the prime numbers up to the
                ' square root of numberToTest.
                Dim primes As ArrayList = BuildPrimeNumberList( _
                    numberToTest, asyncOp)
    
                ' Now we have a list of primes less than 
                'numberToTest.
                prime = IsPrime( _
                    primes, _
                    numberToTest, _
                    firstDivisor)
    
            Catch ex As Exception
                exc = ex
            End Try
    
        End If
    
        Me.CompletionMethod( _
            numberToTest, _
            firstDivisor, _
            prime, _
            exc, _
            TaskCanceled(asyncOp.UserSuppliedState), _
            asyncOp)
    
    End Sub
    
  3. uygulayın BuildPrimeNumberList. İki parametre alır: test etmek için sayı ve bir AsyncOperation. İlerleme durumunu ve artımlı sonuçları raporlamak için öğesini AsyncOperation kullanır. Bu, istemcinin olay işleyicilerinin uygulama modeli için uygun iş parçacığında veya bağlamda çağrılmalarını sağlar. BuildPrimeNumberList Bir asal sayı bulduğunda, bunu olay için ProgressChanged istemcinin olay işleyicisine artımlı bir sonuç olarak bildirir. Bu, adlı LatestPrimeNumberbir özelliği eklenmiş olan adlı CalculatePrimeProgressChangedEventArgsöğesinden ProgressChangedEventArgstüretilmiş bir sınıf gerektirir.

    yöntemi BuildPrimeNumberList de düzenli aralıklarla yöntemini çağırır TaskCanceled ve yöntemi döndürürse trueyönteminden çıkar.

    // This method computes the list of prime numbers used by the
    // IsPrime method.
    private ArrayList BuildPrimeNumberList(
        int numberToTest,
        AsyncOperation asyncOp)
    {
        ProgressChangedEventArgs e = null;
        ArrayList primes = new ArrayList();
        int firstDivisor;
        int n = 5;
    
        // Add the first prime numbers.
        primes.Add(2);
        primes.Add(3);
    
        // Do the work.
        while (n < numberToTest &&
               !TaskCanceled( asyncOp.UserSuppliedState ) )
        {
            if (IsPrime(primes, n, out firstDivisor))
            {
                // Report to the client that a prime was found.
                e = new CalculatePrimeProgressChangedEventArgs(
                    n,
                    (int)((float)n / (float)numberToTest * 100),
                    asyncOp.UserSuppliedState);
    
                asyncOp.Post(this.onProgressReportDelegate, e);
    
                primes.Add(n);
    
                // Yield the rest of this time slice.
                Thread.Sleep(0);
            }
    
            // Skip even numbers.
            n += 2;
        }
    
        return primes;
    }
    
    ' This method computes the list of prime numbers used by the
    ' IsPrime method.
    Private Function BuildPrimeNumberList( _
        ByVal numberToTest As Integer, _
        ByVal asyncOp As AsyncOperation) As ArrayList
    
        Dim e As ProgressChangedEventArgs = Nothing
        Dim primes As New ArrayList
        Dim firstDivisor As Integer
        Dim n As Integer = 5
    
        ' Add the first prime numbers.
        primes.Add(2)
        primes.Add(3)
    
        ' Do the work.
        While n < numberToTest And _
            Not Me.TaskCanceled(asyncOp.UserSuppliedState)
    
            If IsPrime(primes, n, firstDivisor) Then
                ' Report to the client that you found a prime.
                e = New CalculatePrimeProgressChangedEventArgs( _
                    n, _
                    CSng(n) / CSng(numberToTest) * 100, _
                    asyncOp.UserSuppliedState)
    
                asyncOp.Post(Me.onProgressReportDelegate, e)
    
                primes.Add(n)
    
                ' Yield the rest of this time slice.
                Thread.Sleep(0)
            End If
    
            ' Skip even numbers.
            n += 2
    
        End While
    
        Return primes
    
    End Function
    
  4. uygulayın IsPrime. Üç parametre alır: bilinen asal sayıların listesi, test edilen sayı ve bulunan ilk bölen için bir çıkış parametresi. Asal sayıların listesi göz önüne alındığında, test sayısının asal olup olmadığını belirler.

    // This method tests n for primality against the list of
    // prime numbers contained in the primes parameter.
    private bool IsPrime(
        ArrayList primes,
        int n,
        out int firstDivisor)
    {
        bool foundDivisor = false;
        bool exceedsSquareRoot = false;
    
        int i = 0;
        int divisor = 0;
        firstDivisor = 1;
    
        // Stop the search if:
        // there are no more primes in the list,
        // there is a divisor of n in the list, or
        // there is a prime that is larger than
        // the square root of n.
        while (
            (i < primes.Count) &&
            !foundDivisor &&
            !exceedsSquareRoot)
        {
            // The divisor variable will be the smallest
            // prime number not yet tried.
            divisor = (int)primes[i++];
    
            // Determine whether the divisor is greater
            // than the square root of n.
            if (divisor * divisor > n)
            {
                exceedsSquareRoot = true;
            }
            // Determine whether the divisor is a factor of n.
            else if (n % divisor == 0)
            {
                firstDivisor = divisor;
                foundDivisor = true;
            }
        }
    
        return !foundDivisor;
    }
    
    ' This method tests n for primality against the list of 
    ' prime numbers contained in the primes parameter.
    Private Function IsPrime( _
        ByVal primes As ArrayList, _
        ByVal n As Integer, _
        ByRef firstDivisor As Integer) As Boolean
    
        Dim foundDivisor As Boolean = False
        Dim exceedsSquareRoot As Boolean = False
    
        Dim i As Integer = 0
        Dim divisor As Integer = 0
        firstDivisor = 1
    
        ' Stop the search if:
        ' there are no more primes in the list,
        ' there is a divisor of n in the list, or
        ' there is a prime that is larger than 
        ' the square root of n.
        While i < primes.Count AndAlso _
            Not foundDivisor AndAlso _
            Not exceedsSquareRoot
    
            ' The divisor variable will be the smallest prime number 
            ' not yet tried.
            divisor = primes(i)
            i = i + 1
    
            ' Determine whether the divisor is greater than the 
            ' square root of n.
            If divisor * divisor > n Then
                exceedsSquareRoot = True
                ' Determine whether the divisor is a factor of n.
            ElseIf n Mod divisor = 0 Then
                firstDivisor = divisor
                foundDivisor = True
            End If
        End While
    
        Return Not foundDivisor
    
    End Function
    
  5. CalculatePrimeProgressChangedEventArgs'den ProgressChangedEventArgstüretilir. Bu sınıf, artımlı sonuçları olay için istemcinin olay işleyicisine raporlamak ProgressChanged için gereklidir. adlı LatestPrimeNumberek bir özelliği vardır.

    public class CalculatePrimeProgressChangedEventArgs :
            ProgressChangedEventArgs
    {
        private int latestPrimeNumberValue = 1;
    
        public CalculatePrimeProgressChangedEventArgs(
            int latestPrime,
            int progressPercentage,
            object userToken) : base( progressPercentage, userToken )
        {
            this.latestPrimeNumberValue = latestPrime;
        }
    
        public int LatestPrimeNumber
        {
            get
            {
                return latestPrimeNumberValue;
            }
        }
    }
    
    Public Class CalculatePrimeProgressChangedEventArgs
        Inherits ProgressChangedEventArgs
        Private latestPrimeNumberValue As Integer = 1
    
    
        Public Sub New( _
            ByVal latestPrime As Integer, _
            ByVal progressPercentage As Integer, _
            ByVal UserState As Object)
    
            MyBase.New(progressPercentage, UserState)
            Me.latestPrimeNumberValue = latestPrime
    
        End Sub
    
        Public ReadOnly Property LatestPrimeNumber() As Integer
            Get
                Return latestPrimeNumberValue
            End Get
        End Property
    End Class
    

Denetim noktası 3

Bu noktada bileşeni oluşturabilirsiniz.

Bileşeninizi test etmek için

  • Bileşeni derleyin.

    Yazılmaya devam eden tek şey, CalculatePrimeAsync zaman uyumsuz işlemleri başlatma ve iptal etme yöntemleridir ve CancelAsync.

Başlatma ve İptal Yöntemlerini Uygulama

Çalışan yöntemini sarmalayan temsilciyi çağırarak BeginInvoke kendi iş parçacığında başlatırsınız. Belirli bir zaman uyumsuz işlemin ömrünü yönetmek için yardımcı sınıfında yöntemini AsyncOperationManager çağırırsınızCreateOperation. Bu, istemcinin olay işleyicilerini uygun iş parçacığına veya bağlama çağıran bir AsyncOperationdöndürür.

Belirli bir bekleyen işlemi ilgili AsyncOperationüzerinde çağırarak PostOperationCompleted iptal edebilirsiniz. Bu işlem bu işlemi sonlandırır ve sonraki çağrılar AsyncOperation bir özel durum oluşturur.

Başlat ve İptal işlevlerini uygulamak için:

  1. CalculatePrimeAsync yöntemini uygulayın. İstemci tarafından sağlanan belirtecin (görev kimliği) şu anda bekleyen görevleri temsil eden tüm belirteçlere göre benzersiz olduğundan emin olun. İstemci benzersiz olmayan bir belirteç geçirirse bir CalculatePrimeAsync özel durum oluşturur. Aksi takdirde, belirteç görev kimliği koleksiyonuna eklenir.

    // This method starts an asynchronous calculation.
    // First, it checks the supplied task ID for uniqueness.
    // If taskId is unique, it creates a new WorkerEventHandler
    // and calls its BeginInvoke method to start the calculation.
    public virtual void CalculatePrimeAsync(
        int numberToTest,
        object taskId)
    {
        // Create an AsyncOperation for taskId.
        AsyncOperation asyncOp =
            AsyncOperationManager.CreateOperation(taskId);
    
        // Multiple threads will access the task dictionary,
        // so it must be locked to serialize access.
        lock (userStateToLifetime.SyncRoot)
        {
            if (userStateToLifetime.Contains(taskId))
            {
                throw new ArgumentException(
                    "Task ID parameter must be unique",
                    "taskId");
            }
    
            userStateToLifetime[taskId] = asyncOp;
        }
    
        // Start the asynchronous operation.
        WorkerEventHandler workerDelegate = new WorkerEventHandler(CalculateWorker);
        workerDelegate.BeginInvoke(
            numberToTest,
            asyncOp,
            null,
            null);
    }
    
    ' This method starts an asynchronous calculation. 
    ' First, it checks the supplied task ID for uniqueness.
    ' If taskId is unique, it creates a new WorkerEventHandler 
    ' and calls its BeginInvoke method to start the calculation.
    Public Overridable Sub CalculatePrimeAsync( _
        ByVal numberToTest As Integer, _
        ByVal taskId As Object)
    
        ' Create an AsyncOperation for taskId.
        Dim asyncOp As AsyncOperation = _
            AsyncOperationManager.CreateOperation(taskId)
    
        ' Multiple threads will access the task dictionary,
        ' so it must be locked to serialize access.
        SyncLock userStateToLifetime.SyncRoot
            If userStateToLifetime.Contains(taskId) Then
                Throw New ArgumentException( _
                    "Task ID parameter must be unique", _
                    "taskId")
            End If
    
            userStateToLifetime(taskId) = asyncOp
        End SyncLock
    
        ' Start the asynchronous operation.
        Dim workerDelegate As New WorkerEventHandler( _
            AddressOf CalculateWorker)
    
        workerDelegate.BeginInvoke( _
            numberToTest, _
            asyncOp, _
            Nothing, _
            Nothing)
    
    End Sub
    
  2. CancelAsync yöntemini uygulayın. taskId Parametre belirteç koleksiyonunda varsa kaldırılır. Bu, başlatılmamış iptal edilen görevlerin çalışmasını engeller. Görev çalışıyorsa, görev kimliğinin BuildPrimeNumberList yaşam süresi koleksiyonundan kaldırıldığını algıladığında yöntem çıkar.

    // This method cancels a pending asynchronous operation.
    public void CancelAsync(object taskId)
    {
        AsyncOperation asyncOp = userStateToLifetime[taskId] as AsyncOperation;
        if (asyncOp != null)
        {
            lock (userStateToLifetime.SyncRoot)
            {
                userStateToLifetime.Remove(taskId);
            }
        }
    }
    
    ' This method cancels a pending asynchronous operation.
    Public Sub CancelAsync(ByVal taskId As Object)
    
        Dim obj As Object = userStateToLifetime(taskId)
        If (obj IsNot Nothing) Then
    
            SyncLock userStateToLifetime.SyncRoot
    
                userStateToLifetime.Remove(taskId)
    
            End SyncLock
    
        End If
    
    End Sub
    

Denetim noktası 4

Bu noktada bileşeni oluşturabilirsiniz.

Bileşeninizi test etmek için

  • Bileşeni derleyin.

Bileşen PrimeNumberCalculator artık tamamlandı ve kullanıma hazır.

Bileşeni kullanan PrimeNumberCalculator örnek bir istemci için bkz . Nasıl yapılır: Olay Tabanlı Zaman Uyumsuz Desenin İstemcisini Uygulama.

Sonraki Adımlar

Bu örneği, yönteminin zaman uyumlu eşdeğeri CalculatePrimeAsync yazarak CalculatePrimedoldurabilirsiniz. Bu, bileşeni Olay PrimeNumberCalculator Tabanlı Zaman Uyumsuz Desen ile tamamen uyumlu hale getirir.

Farklı test numaraları için çeşitli çağrılar tarafından bulunan tüm asal sayıların listesini tutarak bu örneği geliştirebilirsiniz. Bu yaklaşım kullanıldığında, her görev önceki görevler tarafından yapılan çalışmalardan yararlanacaktır. Bu listeyi bölgelerle lock korumaya dikkat edin, böylece listeye farklı iş parçacıkları tarafından erişim serileştirilir.

Ayrıca 2, 3 ve 5 gibi önemsiz bölenleri test ederek bu örneği geliştirebilirsiniz.

Ayrıca bkz.