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:
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
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)
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
Sınıf tanımından
PrimeNumberCalculator
sonra, her hesaplamanınCalculatePrimeCompletedEventArgs
sonucunu .event için istemcinin olay işleyicisine raporlamak için sınıfını türetinCalculatePrimeCompleted
. ÖzelliklereAsyncCompletedEventArgs
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:
sınıfında temsilcileri
PrimeNumberCalculator
bildirin ve oluşturunSendOrPostCallback. SendOrPostCallback adlıInitializeDelegates
bir 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
InitializeDelegates
Bileşeninizin oluşturucusunda yöntemini çağırın.public PrimeNumberCalculator() { InitializeComponent(); InitializeDelegates(); }
Public Sub New() InitializeComponent() InitializeDelegates() End Sub
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)
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ıuserStateToLifetime
bir 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:
İ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
CalculatePrimeCompletedEventHandler
istemciye döndürülen öğesiniCalculatePrimeCompletedEventArgs
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
, BuildPrimeNumberList
ve IsPrime
. Birlikte ve BuildPrimeNumberList
IsPrime
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 BeginInvoke
zaman 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:
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ürtrue
.// 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
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
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çinProgressChanged
istemcinin olay işleyicisine artımlı bir sonuç olarak bildirir. Bu, adlıLatestPrimeNumber
bir ö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ırTaskCanceled
ve yöntemi döndürürsetrue
yö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
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
CalculatePrimeProgressChangedEventArgs
'den ProgressChangedEventArgstüretilir. Bu sınıf, artımlı sonuçları olay için istemcinin olay işleyicisine raporlamakProgressChanged
için gereklidir. adlıLatestPrimeNumber
ek 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 veCancelAsync
.
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:
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 birCalculatePrimeAsync
ö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
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ğininBuildPrimeNumberList
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 CalculatePrime
doldurabilirsiniz. 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.