.net5 core webapi进阶之四:异步编程(下篇)BeginInvoke( )/EndInvoke( )的使用

实现异步操作,除了用 async 和 await 这对组合之外,还可以通过委托对象的 BeginInvoke( ) 和 EndInvoke( ) 来完成 ,

为简单起见,我们直接使用系统为我们提供的内置委托 Func<T1,T2,...TResult>(或者不带返回值的Action<T1,T2...>委托也可以) ,代码如下:

(注:目前.net5 core 还不支持 BeginInvoke() 和 EndInvoke() 这种异步调用形式,需要用 .net5  framework环境 。)

  class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            Console.WriteLine("Main Thread ID = " + Thread.CurrentThread.ManagedThreadId);

            Demo51();

            Console.ReadLine();
        }
         
        private static int Demo51()
        {
            //定义一个Func<int,int>类型的委托 fx,功能:输入一个整数,+100后输出。
            Func<int, int> fx = new Func<int, int>(
                x => {
                    Console.WriteLine("Func<int, int>() Thread ID = " + Thread.CurrentThread.ManagedThreadId); 
                    return x + 100; 
                }
            );

            int ret = fx.Invoke(28); // Invoke() 是同步调用,即在当前主线程中调用 fx

            // BeginInvoke() 是异步调用,主线程会在线程池中取一个新线程来执行 fx,主线程会继续往下执行
            IAsyncResult iar = fx.BeginInvoke(28, null, null);
    
            // do something1....这里可以加入业务代码

            // EndInvoke() 用于获取 fx 的执行结果并释放线程使用的资源,在获取到结果之前主线程不会继续往下执行
            int val = fx.EndInvoke(iar);
 
            // do something2....这里可以加入业务代码

            return val;
        } 
    }

 运行程序其结果如下,可以看到调用 fx.Invoke( ) 和 fx.BeginInvoke( )的运行线程是不一样的。

 

在上面的例子中,当主线程执行到 "int val = fx.EndInvoke(iar);" 这条语句时如果 fx 还未执行完成,

主线程不会继续往下执行,会一直等待 fx 的执行结果,这种方式叫 "等待直到完成(wait-until-done)" 模式 ,

除了这种模式外,还有另外2种模式,分别是 "轮询(polling)"模式 和 "回调(callback)"模式,具体如下:

 

2. 轮询(polling)模式

     private int Demo52()
        {

       //定义一个Func<int,int>类型的委托 fx,功能:输入一个整数,+100后输出。 Func<int, int> fx = new Func<int, int>( x => { Console.WriteLine("Func<int, int>() Thread ID = " + Thread.CurrentThread.ManagedThreadId); return x + 100; } );

// BeginInvoke() 是异步调用,即在线程池中取一个新线程来执行 fx IAsyncResult iar = fx.BeginInvoke(28, null, null); // do something1....这里可以加入业务代码 // 判断 IAsyncResult.IsCompleted 属性来轮询 fx 是否执行完成 while (iar.IsCompleted == false) { // do something....这里可以加入业务代码 } // EndInvoke() 用于获取 fx 的执行结果并释放线程使用的资源 int val = fx.EndInvoke(iar); // do something2....这里可以加入业务代码 return val; }

轮询(polling)模式通过 IAsyncResult.IsCompleted 属性来判断 fx 是否执行完成 ,

我们可以在完成前和完成后做一些业务处理(测试略)。

 

3. 回调(callback)模式

        private int callbackResult=0;
        private void CallbackFunc(IAsyncResult iar)
        {
            // state="test param",对应fx.BeginInvoke()的最后一个参数
            string state = (string)iar.AsyncState;

            // 强制转型用于后面获取委托对象 fx
            AsyncResult ar = (AsyncResult)iar;
            Func<int, int> fx = (Func<int, int>)ar.AsyncDelegate;

            int callbackResult = fx.EndInvoke(iar);
        }
        private int Demo53()
        {
        //定义一个Func<int,int>类型的委托 fx,功能:输入一个整数,+100后输出。
            Func<int, int> fx = new Func<int, int>(
                x => {
                    Console.WriteLine("Func<int, int>() Thread ID = " + Thread.CurrentThread.ManagedThreadId); 
                    return x + 100; 
                }
            );

// BeginInvoke() 是异步调用,即在线程池中取一个新线程来执行 fx IAsyncResult iar = fx.BeginInvoke(28, CallbackFunc, "test param"); // do something....这里可以加入业务代码 // 在回调方法执行完成前,此值是0。 return callbackResult; }

回调(callback)模式中, fx.BeginInvoke( )第二个参数对应的回调函数 CallbackFunc 的签名必须符合

"void FuncName(IAsyncResult iar)" 的形式,最后一个参数是 object 类型,

可以传入任意对象,在回调函数中用 iar.AsyncState 取值后做强制转型就可以了(测试略)。

 

=================================分割线=================================

除了 async / await 和 delegate.BeginInvoke( ) / EndInvoke( ) 可以进行异步操作之外,

.net 还为我们提供了 System.Threading.Timer 、System.Threading.Tasks.Parallel 、

System.ComponentModel.BackgroundWorker 等类来做并行处理,

它们中部分更适用于GUI环境(如winform、WPF等),后续根据需要再做介绍。

 

posted @ 2021-02-27 13:16  屏风马  阅读(1518)  评论(0编辑  收藏  举报