神麽是异步调用
在主线程中异步调用的方法不在主线程中执行,而是在另一个辅助线程中与主线程代码并行执行。给出一段示例代码:
当我们调用UploadPictureAsync方法时,图片尚未上传完成,我们就可以在控制台输出提示信息:“图片开始上传”。
/// <summary> /// 异步上传图片 /// </summary> /// <param name="fileLocalPath"></param> public void UploadPictureAsync(string id, string fileLocalPath) { DelegateMgr.UploadFileHandler del = new DelegateMgr.UploadFileHandler(UploadFile); del.BeginInvoke(id, fileLocalPath, delegate(IAsyncResult ar) { try { string fileUri = del.EndInvoke(ar); FileUploadEventArgs args = new FileUploadEventArgs(id, fileUri); if (PictureUploadCompleted != null) { PictureUploadCompleted(args); } } catch (Exception ex) { LogUtility.LogTableMessage("图片上传异常," + ex); } }, null);
Console.WriteLine("图片开始上传" ); } private string UploadFile(string id, string filePath) { string fileUri = string.Empty; try { WebClient wc = new WebClient(); string targetPath = "http://172.16.50.179:8090/FileUpload/ImageUpLoad.do"; byte[] bytes = wc.UploadFile(targetPath, "POST", filePath); fileUri = Encoding.Default.GetString(bytes);
Console.WriteLine("图片完成上传" ); } catch (Exception exception) { LogUtility.LogTableMessage("上传图片异常," + exception); } return fileUri; } public event Action<FileUploadEventArgs> PictureUploadCompleted;
编译器对委托都做了些神麽。。。
当我们定义一个委托时,编译器会为委托生成一个类。比如我们定义如下委托:
public delegate int DemoDelegate(int a, int b);
编译器会生成如下格式的类:
public sealed class DemoDelegate : MulticastDelegate { public DemoDelegate(object @object, IntPtr method) { // } public virtual int Invoke(int a, int b) { //方法体为空 } public virtual IAsyncResult BeginInvoke(int a, int b, AsyncCallback callback, object asyncState) { //方法体为空 } public virtual int EndInvoke(IAsyncResult ar) { //方法体为空 } }
同步调用实现
class Program { static void Main(string[] args) { DemoDelegate del = new DemoDelegate(Add); //同步调用 Console.WriteLine("1 + 2 = " + del(1, 2)); } static int Add(int a, int b) { return a + b; } }
上面这种同步调用方式,实际上调用的是委托类的 Invoke 方法。
异步调用实现
基于委托的异步调用,实际上是通过 BeginInvoke 和 EndInvoke 两个方法来实现的。
我们先来分析一下BeginInvoke方法
public IAsyncResult BeginInvoke(
<输入和输出变量>,
AsyncCallback callback, object asyncState
)
<输入和输出变量>,表示委托声明中,参数有ref或者out修饰的。
callback,异步调用结束时自动回调的方法
asyncState,用于向callback方法提供参数信息,比如回调方法需要一些参数,asyncState 就可以用于填充这些参数。
对BeginInvoke方法的返回类型 IAsyncResult接口的说明
[ComVisible(true)] public interface IAsyncResult { object AsyncState { get; } WaitHandle AsyncWaitHandle { get; } bool CompletedSynchronously { get; } bool IsCompleted { get; } }
AsyncState,直接存储BeginInvoke方法中传入的 asyncState 参数值
AsyncWaitHandle,当异步操作完成时,该句柄处于 signaled 状态。
CompletedSynchronously,表示BeginInvoke是否同步调用完成。
IsCompleted,可以通过循环查询该属性判断异步操作是否完成。
接下来我们分析一下 EndInvoke 方法
public <方法返回值类型> EndInvoke(
<声明为ref或out的参数>,
IAsyncResult result)
调用 BeginInvoke方法会返回一个类型为 IAsyncResult 的对象,该对象会作为 EndInvoke方法的参数,这样EndInvoke方法不断轮询异步执行结果,发现异步调用完成时,会将异步调用结果作为返回值,如果异步调用方法有 ref 或者 out参数,也会负责填充这些参数。
调用者线程 辅助线程
|
①BeginInvoke ------------------------>
| ②异步调用方法执行
③EndInvoke <-------------------------