Heim >Backend-Entwicklung >C#.Net-Tutorial >Teilen von Beispielen für die asynchrone Programmentwicklung im C#-Asynchron-APM-Modus

Teilen von Beispielen für die asynchrone Programmentwicklung im C#-Asynchron-APM-Modus

黄舟
黄舟Original
2018-05-11 11:32:561964Durchsuche

C# hat eine Geschichte von mehr als 10 Jahren, gemessen am Update-Fortschritt von Microsoft, der auch die Entwicklung mehrerer Versionen erlebt Reihe von Blogbeiträgen zum Aufzeichnen Werfen wir einen Blick auf die Entwicklungsgeschichte der asynchronen Programmierung in C#. Werbung: Freunde, denen mein Artikel gefällt, klicken bitte unten auf „Folge mir“. Vielen Dank

Ich bin 2004 mit C# in Kontakt gekommen und habe es verwendet. Die C#-Version war damals 1.1, daher werden wir ab diesem Zeitpunkt mit dem Gespräch beginnen. Zu dieser Zeit habe ich im College selbst Programme gelesen und geschrieben. Die meisten Programme, die ich geschrieben habe, waren synchrone Programme, und es konnte höchstens ein Thread gestartet werden ... Tatsächlich gab es in der Ära von C # 1.1 einen vollständigen asynchrone Programmierlösung, und das war APM (Asynchrones Programmiermodell). Wenn Sie „synchrone Programme und asynchrone Programme“ immer noch nicht verstehen, wenden Sie sich bitte an Baidu.

Das repräsentativste Merkmal des asynchronen APM-Programmiermodells ist, dass eine asynchrone Funktion aus zwei Methoden besteht, beginnend mit Begin und End. Die Methode, die mit Begin beginnt, bedeutet, die Ausführung der asynchronen Funktion zu starten, und die Methode, die mit End beginnt, bedeutet, darauf zu warten, dass die Ausführung der asynchronen Funktion abgeschlossen ist, und das Ausführungsergebnis zurückzugeben. Das Folgende ist eine Simulationsimplementierung (die asynchrone Standardimplementierung des APM-Modells wird später geschrieben):

public class Worker
    {        
    public int A { get; set; }        
    public int B { get; set; }        
    private int R { get; set; }
        ManualResetEvent et;        
        public void BeginWork(Action action)
        {
            et = new ManualResetEvent(false);            
            new Thread(() =>
            {
                R = A + B;
                Thread.Sleep(1000);
                et.Set();                
                if(null != action)
                {
                    action();
                }
            }).Start();
        }        public int EndWork()
        {            if(null == et)
            {                t
            hrow new Exception("调用EndWork前,需要先调用BeginWork");
            }            
            else
            {
                et.WaitOne();                
                return R;
            }

        } 
    }
        static void Main(string[] args)
        {
           Worker w = new Worker();
            w.BeginWork(()=> {
                Console.WriteLine("Thread Id:{0},Count:{1}", Thread.CurrentThread.ManagedThreadId,
                    w.EndWork());
            });
            Console.WriteLine("Thread Id:{0}", Thread.CurrentThread.ManagedThreadId);
            Console.ReadLine();
        }

Im obigen Simulations-APM-Modell haben wir Thread und ManualResetEvent verwendet. Threading Wenn Sie mit ManualResetEvent nicht vertraut sind, erfordert die Verwendung der asynchronen Programmierung in C# zwangsläufig Multithreading-Kenntnisse. Obwohl Microsoft im Framework viel Kapselung vorgenommen hat, sollten Freunde das Wesentliche verstehen.

Der Grund, warum das oben simulierte asynchrone APM-Modell einfach ist, liegt darin, dass während der Entwicklung von C# viele hervorragende Syntaxregeln eingeführt wurden. Im obigen Beispiel haben wir häufiger Lambda-Ausdrücke verwendet. Wenn Sie mit anonymen Delegaten und Lambda-Ausdrücken nicht vertraut sind, können Sie mein vorheriges Bolg „Anonyme Delegaten und Lambda-Ausdrücke“ lesen. Es gibt so viele Anzeigen oben, schauen wir uns an, wie das Standard-APM-Modell die asynchrone Programmierung implementiert.

IAsyncResult-Schnittstelle

IAsyncResult-Schnittstelle definiert den Status asynchroner Funktionen. Die spezifischen Attribute und Bedeutungen dieser Schnittstelle sind wie folgt:

   //     表示异步操作的状态。
    [ComVisible(true)]    public interface IAsyncResult
    {        //
        // 摘要:        //     获取一个值,该值指示异步操作是否已完成。        //
        // 返回结果:        //     如果操作已完成,则为 true;否则为 false。
        bool IsCompleted { get; }        //
        // 摘要:        //     获取用于等待异步操作完成的 System.Threading.WaitHandle。        //
        // 返回结果:        //     用于等待异步操作完成的 System.Threading.WaitHandle。
        WaitHandle AsyncWaitHandle { get; }        //
        // 摘要:        //     获取一个用户定义的对象,该对象限定或包含有关异步操作的信息。        //
        // 返回结果:        //     一个用户定义的对象,限定或包含有关异步操作的信息。
        object AsyncState { get; }        //
        // 摘要:        //     获取一个值,该值指示异步操作是否同步完成。        //
        // 返回结果:        //     如果异步操作同步完成,则为 true;否则为 false。
        bool CompletedSynchronously { get; }
    }

Hinweis: Modellbeispiel ManualResetEvent in 1 erbt von WaitHandle
APM-Legenden-Implementierungsmethode
Nachdem wir die IAsyncResult-Schnittstelle verstanden haben, werden wir das Umschreiben des Simulationsbeispiels durch Implementierung der IAsyncResult-Schnittstelle abschließen. Der Code lautet wie folgt:

    public class NewWorker
    {        public class WorkerAsyncResult : IAsyncResult
        {
            AsyncCallback callback;            
            public WorkerAsyncResult(int a,int b, AsyncCallback callback, object asyncState) {
                A = a;
                B = b;
                state = asyncState;                
                this.callback = callback;                
                new Thread(Count).Start(this);
            }            
            public int A { get; set; }            
            public int B { get; set; }            
            public int R { get; private set; }            
            private object state;            
            public object AsyncState
            {                
            get
                {                    
                return state;
                }
            }            
            private ManualResetEvent waitHandle;            
            public WaitHandle AsyncWaitHandle
            {                
            get
                {                    
                if (null == waitHandle)
                    {
                        waitHandle = new ManualResetEvent(false);
                    }                    
                    return waitHandle;
                }
            }            private bool completedSynchronously;            
            public bool CompletedSynchronously
            {                get
                {                    
                return completedSynchronously;
                }
            }            
            private bool isCompleted;            
            public bool IsCompleted
            {                
            get
                {                    
                return isCompleted;
                }
            }            
            private static void Count(object state)
            {                
            var result = state as WorkerAsyncResult;
                result.R = result.A + result.B;
                Thread.Sleep(1000);
                result.completedSynchronously = false;
                result.isCompleted = true;
                ((ManualResetEvent)result.AsyncWaitHandle).Set();                
                if (result.callback != null)
                {
                    result.callback(result);
                }
            }
        }        
        public int Num1 { get; set; }        
        public int Num2 { get; set; }        
        public IAsyncResult BeginWork(AsyncCallback userCallback, object asyncState)
        {
            IAsyncResult result = new WorkerAsyncResult(Num1,Num2,userCallback, asyncState);            
            return result;
        }        public int EndWork(IAsyncResult result)
        {
            WorkerAsyncResult r = result as WorkerAsyncResult;
            r.AsyncWaitHandle.WaitOne();            return r.R;
        }
    }

Beispielcode-Analyse:

Im obigen Code ist die interne Klasse WorkerAsyncResult von NewWorker der Schlüsselpunkt. Sie implementiert die IAsyncResult-Schnittstelle und ist für das Starten eines neuen Threads verantwortlich, um die Berechnungsarbeit abzuschließen.

Zwei private Attribute A und B werden zu WorkerAsyncResult hinzugefügt, um die für die Berechnung verwendeten Werte zu speichern, und ein extern lesbares, aber nicht beschreibbares Attribut R wird verwendet, um die Ergebnisse der internen Operation von WorkerAsyncResult zu speichern. Auf die AsyncWaitHandle-Eigenschaft wirkt ein ManualResetEvent ein, und beim ersten Zugriff wird ein ManualResetEvent erstellt (aber nicht freigegeben). Andere Schnittstelleneigenschaften werden normal implementiert, dazu gibt es nichts zu sagen.

Neue statische Count-Methode wurde zu WorkerAsyncResult hinzugefügt. Der Parameterstatus ist das aktuelle WorkerAsyncResult-Objekt, das die Count-Methode aufruft. Die Count-Methode wird im neu gestarteten Thread des WorkerAsyncResult-Objekts ausgeführt, sodass Thread.Sleep(1000) den neuen Thread 1 Sekunde lang blockiert. Legen Sie dann fest, ob das aktuelle WorkerAsyncResult-Objekt synchron abgeschlossen ist und der asynchrone Abschlussstatus wahr ist. Geben Sie die ManualResetEvent-Benachrichtigung frei, um darauf zu warten, dass der Thread die Benachrichtigung erhält und in den Ausführungsstatus wechselt und rufen Sie es zurück, falls es existiert.

NewWorker ist sehr einfach. Die beiden Attribute Num1 und Num2 sind die zu berechnenden Werte. BeginWork erstellt ein WorkerAsyncResult-Objekt und übergibt die beiden zu berechnenden Werte Num1, Num2, userCallback-Callback-Delegat und Objekttyp asyncState an das zu erstellende WorkerAsyncResult-Objekt. Nach diesem Schritt erhält das WorkerAsyncResult-Objekt alle für den Vorgang erforderlichen Daten, den Rückruf nach Abschluss des Vorgangs und startet sofort einen neuen Thread, um den Vorgang auszuführen (führen Sie die WorkerAsyncResult.Count-Methode aus).

Da WorkerAsyncResult.Count in einem neuen Thread ausgeführt wird, kann der Status des neuen Threads außerhalb des Threads nicht genau bekannt sein. Um den Bedarf externer Threads an der Synchronisierung mit neuen Threads zu decken, wird die EndWork-Methode zu NewWorker hinzugefügt und der Parametertyp ist IAsyncResult. Um die EndWork-Methode aufzurufen, sollten Sie das von BeginWork erhaltene WorkerAsyncResult-Objekt übergeben. Nachdem die EndWork-Methode das WorkerAsyncResult-Objekt abgerufen hat, rufen Sie die WorkerAsyncResult.AsyncWaitHandle.WaitOne()-Methode auf und warten Sie auf die ManualResetEvent-Benachrichtigung Der Operationsthread hat die Operation abgeschlossen (der Thread ist noch nicht beendet). Der nächste Schritt besteht darin, das Operationsergebnis R abzurufen und zurückzugeben.

Als nächstes folgt das NewWorker-Aufrufprogramm wie folgt:

        static void Main(string[] args)
        {
            NewWorker w2 = new NewWorker();
            w2.Num1 = 10;
            w2.Num2 = 12;
            IAsyncResult r = null;
            r = w2.BeginWork((obj) => {
            Console.WriteLine("Thread Id:{0},Count:{1}",Thread.CurrentThread.ManagedThreadId,
            w2.EndWork(r));
            }, null);
            Console.WriteLine("Thread Id:{0}", Thread.CurrentThread.ManagedThreadId);
            Console.ReadLine();
        }

Der Programmaufrufprozess, den ich einfach in der folgenden Abbildung gezeichnet habe, hilft Ihnen beim Verständnis:

Die asynchrone Programmierung des Standard-APM-Modells ist für Entwickler zu kompliziert. Daher ist die asynchrone Programmierung durch die Implementierung der IAsyncResult-Schnittstelle das der Legende , das gut aussieht, aber nicht nützlich ist (sin, sin, sin...).

Asynchrone Programmierung delegieren (APM-Standardimplementierung)

C#中委托天生支持异步调用(APM模型),任何委托对象后"."就会发现BeginInvoke、EndInvoke、Invoke三个方法。BeginInvoke为异步方式调用委托、EndInvoke等待委托的异步调用结束、Invoke同步方式调用委托。因此上面的标准APM实例,可借助  delegate 进行如下简化。

上面NewWorker使用委托方式改写如下:

<br/>


    public class NewWorker2
    {
        Func81e6d16fda30e0e09fc5f6e0e748fe90 action;        public NewWorker2()
        {
            action = new Func81e6d16fda30e0e09fc5f6e0e748fe90(Work);
        }        public IAsyncResult BeginWork(AsyncCallback callback, object state)
        {            dynamic obj = state;            return action.BeginInvoke(obj.A, obj.B, callback, this);
        }        public int EndWork(IAsyncResult asyncResult)
        {            try
            {                return action.EndInvoke(asyncResult);
            }            catch (Exception ex)
            {                throw ex;
            }
        }        private int Work(int a, int b)
        {
            Thread.Sleep(1000);            return a + b;
        }
    }

调用程序:

        static void Main(string[] args)
        {
            NewWorker2 w2 = new NewWorker2();
            IAsyncResult r = null;
            r = w2.BeginWork((obj) =>
            {
                Console.WriteLine("Thread Id:{0},Count:{1}", Thread.CurrentThread.ManagedThreadId,
                    w2.EndWork(r));
            }, new { A = 10, B = 11 });
            Console.WriteLine("Thread Id:{0}", Thread.CurrentThread.ManagedThreadId);

            Console.ReadLine();
        }

上面的使用委托进行APM异步编程,比实现 IAsyncResult 接口的方式精简太多、更易理解使用。因此这里建议朋友们 delegate 异步调用模型应该掌握起来,而通过实现 IAsyncResult 接口的传说方式看你的喜好吧。 

Das obige ist der detaillierte Inhalt vonTeilen von Beispielen für die asynchrone Programmentwicklung im C#-Asynchron-APM-Modus. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn