基于委托的异步编程实现

神麽是异步调用

在主线程中异步调用的方法不在主线程中执行,而是在另一个辅助线程中与主线程代码并行执行。给出一段示例代码:

当我们调用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)
        {
            //方法体为空
        }
    }
请注意,上面3个方法都是虚方法virtual,并且方法体都为空。

同步调用实现

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      <-------------------------                         

标签:
本文系转载文章,感谢原作者的辛勤付出!
交流QQ群:32261424
Previous:
Next:

发表评论

,将以游客形式发表

网友最新评论(0)