C#은 10년이 넘는 역사를 가지고 있으며, 2년마다 진행되는 Microsoft의 업데이트 진행 상황을 보면 매우 역동적입니다. C#의 비동기 프로그래밍도 여러 버전의 진화를 경험했습니다. C#을 기록하기 위한 게시물입니다. 광고: 내 글을 좋아하는 친구들은 아래 "팔로우"를 클릭해주세요. 감사합니다
저는 2004년에 C#을 접해서 사용해봤습니다. 당시 C# 버전은 1.1이었는데, 그때부터 이야기를 시작하겠습니다. 당시 저는 대학에서 혼자서 프로그램을 읽고 작성하고 있었습니다. 제가 작성한 프로그램은 대부분 동기식 프로그램이었으며 최대 한 개의 스레드만 시작할 수 있었습니다... 실제로 C# 1.1 시대에는 완전한 것이 있었습니다. 비동기 프로그래밍 솔루션이 바로 APM(Asynchronous 프로그래밍 모델)이었습니다. 아직도 “동기식 프로그램과 비동기식 프로그램”을 이해하지 못한다면 Baidu를 방문해 보세요.
APM 비동기 프로그래밍 모델의 가장 대표적인 특징은 비동기 함수가 Begin과 End로 시작하는 두 가지 메소드로 구성된다는 것입니다. Begin으로 시작하는 메소드는 비동기 함수의 실행을 시작한다는 의미이고, End로 시작하는 메소드는 비동기 함수의 실행이 완료되기를 기다리고 실행 결과를 반환한다는 의미입니다. 다음은 시뮬레이션 구현입니다(표준 APM 모델 비동기 구현은 나중에 작성됩니다).
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(); }
위 시뮬레이션 APM 모델에서는 Thread 및 ManualResetEvent를 사용했습니다. 멀티스레딩 및 ManualResetEvent에 익숙하지 않은 경우 비동기 프로그래밍을 사용하세요. C# 필연적으로 멀티스레딩 지식이 필요합니다. Microsoft가 Framework에서 많은 캡슐화를 수행했지만 친구들은 그 본질을 파악해야 합니다.
위에서 시뮬레이션한 APM 비동기 모델이 간단한 이유는 C# 개발 과정에서 우수한 문법 규칙이 많이 도입되었기 때문입니다. 위의 예에서는 람다 표현식을 더 많이 사용했습니다. 익명 대리자 및 람다 표현식에 익숙하지 않은 경우 이전 Bolg "익명 대리자 및 람다 표현식"을 읽어보세요. 위에는 광고가 너무 많습니다. 표준 APM 모델이 비동기 프로그래밍을 구현하는 방법을 살펴보겠습니다.
IAsyncResult 인터페이스
IAsyncResult 인터페이스는 비동기 함수의 상태를 정의합니다. 이 인터페이스의 구체적인 속성과 의미는 다음과 같습니다.
// 表示异步操作的状态。 [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; } }
참고: 모델 예제 1의 ManualResetEvent는 WaitHandle
APM 전설적인 구현 방법을 상속합니다
이해한 후 IAsyncResult 인터페이스 마지막으로 IAsyncResult 인터페이스를 구현하여 시뮬레이션 예제의 재작성을 완료합니다. 코드는 다음과 같습니다.
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; } }
샘플 코드 분석:
위 코드에서 NewWorker의 내부 클래스 WorkerAsyncResult가 핵심입니다. IAsyncResult 인터페이스를 구현하고 이에 의해 제어됩니다. 계산 작업을 완료하기 위해 새 스레드를 시작합니다.
WorkerAsyncResult에는 계산에 사용되는 값을 저장하기 위해 두 개의 전용 속성 A와 B가 추가되고, 외부에서 읽을 수 있고 쓸 수 없는 속성 R은 WorkerAsyncResult의 내부 작업 결과를 저장하는 데 사용됩니다. AsyncWaitHandle 속성은 ManualResetEvent에 의해 작동되며 첫 번째 액세스 시 ManualResetEvent가 생성됩니다(해제되지는 않음). 다른 인터페이스 속성은 정상적으로 구현되므로 말할 것도 없습니다.
WorkerAsyncResult에 새로운 정적 Count 메서드가 추가되었으며, 매개 변수 상태는 Count 메서드를 호출하는 현재 WorkerAsyncResult 개체입니다. Count 메서드는 WorkerAsyncResult 개체의 새로 시작된 스레드에서 실행되므로 Thread.Sleep(1000)은 1초 동안 새 스레드를 차단합니다. 그런 다음 현재 WorkerAsyncResult 객체가 동기적으로 완료되는지 여부를 false로 설정하고 비동기 완료 상태가 true인지를 설정하여 스레드가 알림을 받을 때까지 기다리고 비동기 실행 종료 콜백 대리자가 있는지 확인합니다. , 존재하는 경우 다시 호출합니다.
NewWorker는 Num1과 Num2 두 속성이 계산되는 값입니다. BeginWork는 WorkerAsyncResult 객체를 생성하고, 계산할 두 값인 Num1, Num2, userCallback 콜백 대리자 및 객체 유형 asyncState를 생성할 WorkerAsyncResult 객체에 전달합니다. 이 단계가 끝나면 WorkerAsyncResult 객체는 작업에 필요한 모든 데이터와 작업 완료 후 콜백을 획득하고 즉시 새 스레드를 시작하여 작업을 수행합니다(WorkerAsyncResult.Count 메서드 실행).
WorkerAsyncResult.Count는 새로운 스레드에서 실행되기 때문에 스레드 외부에서는 새로운 스레드의 상태를 정확하게 알 수 없습니다. 외부 스레드가 새 스레드와 동기화해야 하는 요구 사항을 충족하기 위해 EndWork 메서드가 NewWorker에 추가되고 매개 변수 유형은 IAsyncResult입니다. EndWork 메서드를 호출하려면 BeginWork에서 얻은 WorkerAsyncResult 개체를 전달해야 합니다. EndWork 메서드가 WorkerAsyncResult 개체를 얻은 후 WorkerAsyncResult.AsyncWaitHandle.WaitOne() 메서드를 호출하고 알림을 받으면 ManualResetEvent 알림을 기다립니다. 작업 스레드가 작업을 완료한 경우(스레드가 종료되지 않음) 다음 단계는 작업 결과 R을 가져와 반환하는 것입니다.
다음 단계는 다음과 같은 NewWorker 호출 프로그램입니다.
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(); }
아래 그림에 제가 간단하게 그린 프로그램 호출 과정은 친구들의 이해에 도움이 될 것입니다.
표준 APM 모델 비동기 프로그래밍, 개발자에 해당 너무 복잡하다고 하더군요. 따라서 IAsyncResult 인터페이스 구현을 통한 비동기 프로그래밍은 전설에 있지만 쓸모가 없습니다(sin, sin, sin...).
비동기 프로그래밍 위임(APM 표준 구현)
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 接口的传说方式看你的喜好吧。
위 내용은 C# 비동기 APM 모드 비동기 프로그램 개발 예제 공유의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!