• 利用委托实现异步


    步骤

    (1)同步方法

    (2)定义类型与同步方法一致的委托

    (3)定义委托变量,与同步方法绑定

    (4)调用委托的BeginInvoke()和EndInvoke(),从而实现异步调用同步方法的效果


    public IAsyncResult BeginInvoke(int p1,out double p2,ref bool p3,AsyncCallBack callback,object AsyncState)
    1. 头几个参数是同步方法的参数
    2. 倒数第二个参数是一个委托,类型是 delegate void AsyncCallBack(IAsyncResult ia);如果被封装的同步方法异步执行结束后,想自动调用某个方法CallbackMethod,则可以将该方法作为倒数第二个参数的实参;如果不需要回调任何方法,则倒数第二个参数为null。
    3. 最后一个参数是异步方法和回调方法之间通信的媒介。如果异步方法无回调函数,则最后一个参数也为null;若有回调函数,那么,如果回调函数需要什么参数,可以打包成一个对象,作为倒数最后一个参数的实参。回调函数内部使用时,需要先进行类型转换。
    4. 返回一个结果,由接口IAsyncResult引用指向。它相当于一个监控,当异步方法被调用,未等执行完毕就先返回,执行后续的代码。在需要的时候,可以通过监控来等待异步方法执行完毕或获取异步方法的运行结果。

        //
        // 摘要:
        //     表示异步操作的状态。
        [ComVisible(true)]
        public interface IAsyncResult
        {
            bool IsCompleted { get; }
            WaitHandle AsyncWaitHandle { get; }
            object AsyncState { get; }
            bool CompletedSynchronously { get; }
        }

    IsCompleted:监控结果.IsCompleted;如果是true,表示异步方法已经执行完毕。

    AsyncWaitHandle:调用它的WaitOne(int times)方法,可以让线程等待异步方法执行完成若干时间。

    AsyncState就是BeginInvoke()的最后一个参数,是传递给回调函数的“信息”。

    CompletedSynchronously:如果异步方法很短,可能在返回监控IAsyncResult之前就已经执行结束,这时候,虽然是异步调用,但是仍旧是同步完成的。此时该变量等于true。


    public 返回值 EndInvoke(out double p2,ref bool p3,IAsyncResult ia )
    1. 头几个参数是同步方法的参数,最后一个参数是BeginInvoke()的返回值。
    2. EndInvoke()的返回值是异步方法的返回值,假设异步方法的返回值是int,则 int res = EndInvoke();如果异步方法无返回值,直接EndInvok();即可。
    3. EndInvoke()是阻塞式的,如果异步方法尚未完成,则会阻塞主调线程,直到异步方法执行完毕。
    4. EndInvoke()会在线程池中清理完成的异步方法,所以务必只要调用了BeginInvoke(),就要调用EndInvoke();
    5. 如果异步方法在执行过程中抛出异常,会在EndInvoke()抛出,所以,如果异步方法可能抛出异常,在EndInvoke()中捕获即可。
    6. EndInvoke()只需要传入out参数,其他参数无需传入。

     示例:

    (1)如果异步方法无回调函数,BeginInvoke()的最后两个参数设为null即可。

    (2)如果异步方法有回调函数,且回调函数无需从外界获取额外的信息,则将回调方法写好,然后作为BeginInvoke()的倒数第二个参数即可;补充:虽然回调函数的参数是IAsyncResult ia,但 是无需将异步方法的BeginInvoke()的返回监控传入,只要将回调函数当做参数,异步方法完成后就会自动执行回调方法。

    最后一个参数是null。

    (3)如果异步方法有回调函数且需要外界“给”一些额外信息,我们可以把额外信息封装成一个对象如【元组】传入。在编写回调函数时,使用前先向下转型,然后进行使用。

    class Program
    {
        public delegate void GetMessageDelegate();
        static GetMessageDelegate GetMessageHnadle;
        static void Main(string[] args)
        {
            GetMessageHnadle += GetMessage;
            GetMessageHnadle.BeginInvoke(CallBackMethod, null);
            Console.Read();
        }
    
        public static void CallBackMethod(IAsyncResult ia)
        {
            Console.WriteLine("i am callback");
        }
    
        public static void GetMessage()
        {
            Console.WriteLine("Data was received successfully.");
            Thread.Sleep(1000);
        }
    }
    class Program
    {
        public delegate void GetMessageDelegate();
        static GetMessageDelegate GetMessageHnadle;
        static void Main(string[] args)
        {
            GetMessageHnadle += GetMessage;
            GetMessageHnadle.BeginInvoke(CallBackMethod, "我是异步方法传入回调函数的信息。");
            Console.Read();
        }
    
        public static void CallBackMethod(IAsyncResult ia)
        {
            Console.WriteLine("i am callback");
            Console.WriteLine(ia.AsyncState as string);
        }
    
        public static void GetMessage()
        {
            Console.WriteLine("Data was received successfully.");
            Thread.Sleep(1000);
        }
    }

    等待异步方法完成的三种方式

    1.

    while(ia.IsCompleted == false)
    {
            waiting....
    }

    2.

    ia.AsyncWaitHandle.WaitOne(100);

    3.

    EndInvoke();

     获取异步方法结果的地点

     调用EndInvoke()需要委托和监控IAysncResult。

    1.如果调用异步方法的主线程,需要获取异步的结果或等待异步方法的完成,那么可以在主调方法中调用EndInvoke();

    2.如果不care异步方法是否执行结束,也无需等待其完成,可以在回调方法中调用EndInvoke();

    class Program
    {
        public delegate string GetMessageDelegate();
        static GetMessageDelegate GetMessageHnadle;
        static void Main(string[] args)
        {
            GetMessageHnadle += GetMessage;
            GetMessageHnadle.BeginInvoke(CallBackMethod, "我是异步方法传入回调函数的信息。");
            Console.Read();
        }
    
        public static void CallBackMethod(IAsyncResult ia)
        {
            AsyncResult ar = ia as AsyncResult;
            GetMessageDelegate del = ar.AsyncDelegate as GetMessageDelegate;
            Console.WriteLine(del.EndInvoke(ia)); 
            Console.WriteLine("i am callback");
            Console.WriteLine(ia.AsyncState as string);
        }
    
        public static string GetMessage()
        {
            Console.WriteLine("Data was received successfully.");
            Thread.Sleep(1000);
            return "异步方法执行完毕";
        }
    }

    尽管IAsyncResult接口没有委托对象的引用,而向下转型得到的AsyncResult类对象却有委托对象的引用。


    番外

    异步方法的回调函数的参数是IAsyncResult类型,只要将异步方法的函数名作为BeginInvoke()的倒数第二个参数即可,监控会自动传入回调函数的!在回调函数中,可以对监控类型转换,能够得到外界传递给回调函数的“信息”,异步方法的委托。

    异步方法和回调函数是完全独立的,可以理解成语法糖。

    其实不调用EndInvoke()时,异步方法可能已经执行完成,EndInvoke()只是取出运行结果,填充out参数和清理线程池而已。

    开启一个线程,线程内容:检测标志位ContinueFlag,若为true,则一直循环执行方法M1。 等价于 ==》 利用M1的委托异步执行M1,M1的回调函数里面检测ContinueFlag,若为true,继续调用M1。

    这就是C#异步服务器的API的原理。

    (1)
    Thread ----> Fun(int a);
    等价于
    Action<int> delegateVar += Fun;
    delegateVar.BeginInvoke(10,null,null);
    可以在回到方法中执行EndInvoke();
    也可以在主调方法中执行EndInvoke();
    (2)
    Thread ----> while(true) { Fun(int a); }
    等价于
    把Fun封装成异步方法,回调函数中再次调用Fun。
  • 相关阅读:
    S5P4418iNand清空方法
    使用 GIT 获得Linux Kernel的代码并查看,追踪历史记录
    Linux3.4内核的基本配置和编译
    uboot---linux
    TestNG的简单使用
    java selenium webdriver处理JS操作窗口滚动条
    testNG入门详解
    零成本实现接口自动化测试 – Java+TestNG 测试Restful service
    Selenium Webdriver——操作隐藏的元素(二)display属性
    python selenium webdriver处理浏览器滚动条
  • 原文地址:https://www.cnblogs.com/liweiaila/p/10513140.html
Copyright © 2020-2023  润新知