• C#同步调用sync与异步调用Async


    0 前言

    1. 同步调用Sync /sɪŋk/
    • 使用Invoke关键字。
    • 为了解决如一边运行程序,一边加载进度条这样的问题。
    • 会堵塞当前线程。
    1. 异步调用Async /əˈsɪŋk/
    • 使用BeginInvoke、EndInvoke关键字。
    • 为了解决主要任务是写作业,趁着写作业烧一壶开水这样的问题。
    • 会堵塞当前线程。

    1 应用介绍

    1. 同步调用
    • 委托的Invoke方法用来进行同步调用。同步调用也可以叫阻塞调用,它将阻塞当前线程,然后执行调用,调用完毕后再继续向下进行。
    • 同步调用的例子:
    using System;
    using System.Threading;
    public delegate int AddHandler(int a, int b);
    public class Foo {
     static void Main() {
      Console.WriteLine("**********SyncInvokeTest**************");
      AddHandler handler = new AddHandler(Add);
      int result = handler.Invoke(1,2);
      Console.WriteLine("Do other work... ... ...");
      Console.WriteLine(result);
      Console.ReadLine();
     }
    
     static int Add(int a, int b) {
      Console.WriteLine("Computing "+a+" + "+b+" ...");
      Thread.Sleep(3000);
      Console.WriteLine("Computing Complete.");
      return a+b;
     }
    }运行结果:
    **********SyncInvokeTest**************
    Computing 1 + 2 ...
    Computing Complete.
    Do other work... ... ...
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    1. 异步调用
    • 同步调用会阻塞线程,如果是要调用一项繁重的工作(如大量IO操作),可能会让程序停顿很长时间,造成糟糕的用户体验,这时候异步调用就很有必要了。

    • 异步调用不阻塞线程,而是把调用塞到线程池中,程序主线程或UI线程可以继续执行。

    • 委托的异步调用通过BeginInvoke和EndInvoke来实现。

    • 异步调用的例子:

    using System;
    using System.Threading;
    public delegate int AddHandler(int a, int b);
    public class Foo {
     static void Main() {
      Console.WriteLine("**********AsyncInvokeTest**************");
      AddHandler handler = new AddHandler(Add);
      IAsyncResult result = handler.BeginInvoke(1,2,null,null);
      Console.WriteLine("Do other work... ... ...");
      Console.WriteLine(handler.EndInvoke(result));
      Console.ReadLine();
     }
    
     static int Add(int a, int b) {
      Console.WriteLine("Computing "+a+" + "+b+" ...");
      Thread.Sleep(3000);
      Console.WriteLine("Computing Complete.");
      return a+b;
     }
    }运行结果: **********AsyncInvokeTest**************
    Do other work... ... ...
    Computing 1 + 2 ...
    Computing Complete.
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    1. 异步调用 + 回调函数
    • 可以看到,主线程并没有等待,而是直接向下运行了。
    • 但是问题依然存在,当主线程运行到EndInvoke时,如果这时调用没有结束(这种情况很可能出现),这时为了等待调用结果,线程依旧会被阻塞。
    • 解决的办法是用回调函数,当调用结束时会自动调用回调函数
    • 异步回调的例子:
    public class Foo {
     static void Main() {
      Console.WriteLine("**********AsyncInvokeTest**************");
      AddHandler handler = new AddHandler(Add);
      IAsyncResult result = handler.BeginInvoke(1,2,new AsyncCallback(AddComplete),"AsycState:OK");
      Console.WriteLine("Do other work... ... ...");
      Console.ReadLine();
     }
    
     static int Add(int a, int b) {
      Console.WriteLine("Computing "+a+" + "+b+" ...");
      Thread.Sleep(3000);
      Console.WriteLine("Computing Complete.");
      return a+b;
     }
    
     static void AddComplete(IAsyncResult result) {
      AddHandler handler = (AddHandler)((AsyncResult)result).AsyncDelegate;
      Console.WriteLine(handler.EndInvoke(result));
      Console.WriteLine(result.AsyncState);
     }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    2 源代码

    我的源代码(.net framework 控制台):

    using System;
    using System.Runtime.Remoting.Messaging;
    using System.Threading;
    
    namespace ConsoleApp2
    {
        class Program
        {
            static void Main(string[] args)
            {
                //0 SyncInvoke 同步调用
                AddHandler addHandler = new AddHandler(Add);//执行委托绑定函数
                int result = addHandler.Invoke(1, 2);//委托同步调用(当前线程暂停)
                Console.WriteLine("Do other work......");//当前线程执行
                Console.WriteLine(result);//输出委托同步执行结果
    
                Thread.Sleep(5000);
                Console.WriteLine();
    
                //2 AsyncInvoke 异步调用
                AddHandler2 addHandler2 = new AddHandler2(Add2);
                IAsyncResult result2 = addHandler2.BeginInvoke(1, 2, null, null);//AsyncCallback为空
                Console.WriteLine("Do other work......");
                Console.WriteLine(addHandler2.EndInvoke(result2));
    
                Thread.Sleep(5000);
                Console.WriteLine();
    
                //3 AsyncInvoke 异步调用 使用AsyncCallback:等到异步调用的结果,再结束主线程
                AddHandler3 addHandler3 = new AddHandler3(Add);
                IAsyncResult result3 = addHandler3.BeginInvoke(1, 2, new AsyncCallback(AddComplete), "AsyncState:OK");
                Console.WriteLine("Do other work......");
                Console.ReadKey();
            }
    
            //0同步调用委托+函数
            public delegate int AddHandler(int a, int b);//定义委托
            public static int Add(int a, int b)//定义委托要执行的函数
            {
                Console.WriteLine("Add " + a + "+" + b + "...");
                Thread.Sleep(10000);
                Console.WriteLine("Add end.");
                return a + b;
            }
    
            //2异步调用委托+函数
            public delegate int AddHandler2(int a, int b);
            public static int Add2(int a, int b)
            {
                Console.WriteLine("Add " + a + "+" + b + "...");
                Thread.Sleep(10000);
                Console.WriteLine("Add end.");
                return a + b;
            }
    
            //3异步调用委托+函数
            public delegate int AddHandler3(int a, int b);
            public static int Add3(int a, int b)
            {
                Console.WriteLine("Add " + a + "+" + b + "...");
                Thread.Sleep(10000);
                Console.WriteLine("Add end.");
                return a + b;
            }
            public static void AddComplete(IAsyncResult result)//返回异步调用的结果
            {
                AddHandler3 handler3 = (AddHandler3)((AsyncResult)result).AsyncDelegate;
                Console.WriteLine(handler3.EndInvoke(result));
                Console.WriteLine(result.AsyncState);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    运行结果:

    在这里可以插入图片描述
    可以看到
    同步调用:在执行委托线程的时候,主线程是阻塞的,委托线程结束后,主线程才继续执行。

    异步调用:在执行委托线程的时候,不影响主线程的执行,所以主线程中的Do other work在委托线程之前执行。但有可能主线程都结束了,委托线程还没执行完返回结果。

    异步回调:执行委托线程的时候,不影响主线程的执行,但是委托线程执行完成的时候,给主线程一个委托线程执行完毕的信号,这样主线程等待委托线程执行完毕,有返回值,才结束主线程。


    3 总结

    同步调用,异步调用,异步回调,经过这次学习,终于理解了一点。本质是委托,再本质是线程,同步异步是与主线程的优先次序不同。

    目前遇到的要解决的问题是在执行一个函数的同时,把值同步传入另一个函数中。肯定要用委托,但是还没解决,这说明对于实际遇到的问题,要分析用哪种技术更加合适。

    对于多线程、同步异步,一定要对实际问题和技术琢磨清楚,然后运用对应的技术就水到渠成。前提是在现实中理解多线程、异步同步,学技术的时候也考虑技术要运用到什么情况中。

  • 相关阅读:
    # Kafka_深入探秘者(7):kafka 稳定性
    像素和分辨率的关系
    四、伊森商城 前端基础-Vue 双向绑定&事件处理&安装插件 p22
    android的rtmp直播推流(一) nginx服务器的搭建
    河南分销小程序开发|商城小程序开发为什么会火?
    新手想开一个传奇该如何操作?开一个传奇必须掌握哪些知识要点
    管理团队技巧+1:问题驱动的测试过程改进
    win11一直弹出用户账户控制怎么解决
    Technology strategy Pattern 学习笔记1-Context: Architecture and Strategy
    eKuiper Newsletter 2022-08|多平台插件一键安装,使用更便捷
  • 原文地址:https://blog.csdn.net/qq_38628970/article/details/126542400