C#异步编程(async and await)及异步方法同步调用

1、什么是异步?

异步操作通常用于执行完成时间可能较长的任务,如打开大文件、连接远程计算机或查询数据库=异步操作在主应用程序线程以外的线程中执行。应用程序调用方法异步执行某个操作时,应用程序可在异步方法执行其任务时继续执行。

2、同步与异步的区别

同步(Synchronous):在执行某个操作时,应用程序必须等待该操作执行完成后才能继续执行。
异步(Asynchronous):在执行某个操作时,应用程序可在异步操作执行时继续执行。实质:异步操作,启动了新的线程,主线程与方法线程并行执行。

3、异步和多线程的区别

我们已经知道, 异步和多线程并不是一个同等关系,异步是最终目的,多线程只是我们实现异步的一种手段。异步是当一个调用请求发送给被调用者,而调用者不用等待其结果的返回而可以做其它的事情。实现异步可以采用多线程技术或则交给另外的进程来处理。

简单的说就是:异步线程是由线程池负责管理,而多线程,我们可以自己控制,当然在多线程中我们也可以使用线程池。

就拿网络扒虫而言,如果使用异步模式去实现,它使用线程池进行管理。异步操作执行时,会将操作丢给线程池中的某个工作线程来完成。当开始I/O操作的时候,异步会将工作线程还给线程池,这意味着获取网页的工作不会再占用任何CPU资源了。直到异步完成,即获取网页完毕,异步才会通过回调的方式通知线程池。可见,异步模式借助于线程池,极大地节约了CPU的资源。

注:DMA(Direct Memory Access)直接内存存取,顾名思义DMA功能就是让设备可以绕过处理器,直接由内存来读取资料。通过直接内存访问的数据交换几乎可以不损耗CPU的资源。在硬件中,硬盘、网卡、声卡、显卡等都有直接内存访问功能。异步编程模型就是让我们充分利用硬件的直接内存访问功能来释放CPU的压力。

两者的应用场景:

  • 计算密集型工作,采用多线程。
  • IO密集型工作,采用异步机制。

C#异步代码参考(async and await)

using System;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncAwaitDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("main start..");
            AsyncMethod();
            Thread.Sleep(1000);
            Console.WriteLine("main end..");

            Console.ReadLine();
        }

        static async void AsyncMethod()
        {
            Console.WriteLine("start async");
            var result = await MyMethod();
            Console.WriteLine("end async");
            //return 1;
        }

        static async Task<int> MyMethod()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Async start:" + i.ToString() + "..");
                await Task.Delay(1000); //模拟耗时操作
            }
            return 0;
        }
    }
}

使用Wait()GetAwaiter().GetResult()方法实现异步方法同步执行

using System;
using System.Threading.Tasks;

namespace AsyncTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Async Test job:");

            Console.WriteLine("main start..");

            Console.WriteLine("MyMethod()异步方法同步执行:");

            MyMethod().Wait();//在main中等待async方法执行完成

            int i = MyMethod().GetAwaiter().GetResult();//用于在main中同步获取async方法的返回结果

            Console.WriteLine("i:" + i);

            Console.WriteLine("main end..");

            Console.ReadKey(true);
        }

        static async Task<int> MyMethod()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Async start:" + i.ToString() + "..");
                await Task.Delay(1000); //模拟耗时操作
            }
            return 0;
        }
    }
}

C# 异步编程 异步委托调用同步方法

同步化操作:

由前后紧接的组件或函数调用组成。一个同步化调用会阻塞整个进程直到这一个操作完成。
在这里插入图片描述

异步化操作:

不会阻塞启动操作的调用线程。调用程序必须通过轮流检测、软件中的中断信号或只是明确地等待完成信号来发现调用的完成。
在这里插入图片描述

.NET 为异步操作提供两种设计模式:

  • 使用 IAsyncResult 对象的异步操作。
  • 使用事件的异步操作。

.NET的许多方面都支持异步编程功能,这些方面包括:

  • 文件 IO、流 IO、套接字 IO。
  • 网络。
  • 远程处理信道(HTTP、TCP)和代理。
  • 使用 ASP.NET 创建的 XML Web services
  • ASP.NET Web 窗体。
  • 使用 MessageQueue 类的消息队列。

异步委托提供以异步方式调用同步方法的能力。

  • 当同步调用一个委托时,调用方法直接对当前线程调用目标方法。如果编译器支持异步委托,则它将生成该调用方法以及BeginInvokeEndInvoke 方法。
  • 如果调用BeginInvoke方法,则公共语言运行库将对请求进行排队并立即返回到调用方。将对来自线程池的线程调用该目标方法。提交请求的原始线程自由地继续与目标方法并行执行,该目标方法是对线程池线程运行的
  • 在回调中,使用EndInvoke 方法来获取返回值和输入/输出参数。如果没有对BeginInvoke指定回调,则可以在提交请求的原始线程上使用EndInvoke
using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;

namespace ClassMain
{
    //委托声明(函数签名)
     delegate string MyMethodDelegate();

    class MyClass
    {
        //要调用的动态方法
        public string MyMethod1()
        {
            return "Hello Word1";
        }

        //要调用的静态方法
        public static string MyMethod2()
        {
            return "Hello Word2";
        }
    }
    class Class1
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            MyClass myClass = new MyClass();

            //方式1:  声明委托,调用MyMethod1
            MyMethodDelegate d = new MyMethodDelegate(myClass.MyMethod1);
            string strEnd = d();
            Console.WriteLine(strEnd);

            //方式2:  声明委托,调用MyMethod2 (使用AsyncResult对象调用)
            d = new MyMethodDelegate(MyClass.MyMethod2); //定义一个委托可以供多个方法使用      
            AsyncResult myResult;   //此类封闭异步委托异步调用的结果,通过AsyncResult得到结果.
            myResult = (AsyncResult)d.BeginInvoke(null, null);        //开始调用

            while (!myResult.IsCompleted)  //判断线程是否执行完成
            {
                Console.WriteLine("正在异步执行MyMethod2 .....");
            }
            Console.WriteLine("方法MyMethod2执行完成!");
            strEnd = d.EndInvoke(myResult);      //等待委托调用的方法完成,并返回结果  
            Console.WriteLine(strEnd);
            Console.Read();
        }
    }
}
### C# 中 `async` 和 `await` 关键字的用法 在 C# 编程语言中,`async` 和 `await` 是用于简化异步编程的关键字。这两个关键字允许开发人员以类似于同步方式编写代码的同时,确保程序不会被长时间运行的操作所阻塞。 #### 定义与作用 - **`async`**: 将方法标记为异步方法,在该方法内可以使用 `await` 来暂停执行直到某个异步操作完成。 - **`await`**: 表达式用来等待一个任务的结果而不阻塞当前线程;只有在一个被声明为 `async` 的函数内部才能使用此表达式[^1]。 #### 基本语法结构 下面展示了一个简单的例子来说明如何定义和调用带有 `async` 和 `await` 的方法: ```csharp public static async Task ExampleMethodAsync() { Console.WriteLine("Starting long-running task..."); // Simulate a time-consuming operation with delay. await Task.Delay(2000); Console.WriteLine("Long-running task completed."); } ``` 在这个例子中,`ExampleMethodAsync()` 被定义成一个返回类型为 `Task` 的异步方法,并且在其体内包含了模拟耗时工作的 `await Task.Delay(2000)` 语句。这表示当遇到这段代码时,控制权会立即交还给调用者,而不需要等到两秒之后再继续向下执行其他部分。 #### 实际应用场景 考虑这样一个场景——从网络获取数据并显示出来。如果采用传统的同步模式,则整个应用可能会因为等待服务器响应而变得无响应。但是借助于 `async` / `await` ,可以在不影响用户体验的情况下优雅地解决这个问题: ```csharp private async void FetchDataButton_Click(object sender, EventArgs e) { try { var data = await GetDataFromServerAsync(); DisplayData(data); } catch (Exception ex){ MessageBox.Show($"Error fetching data: {ex.Message}"); } } // An asynchronous method that simulates getting data from server. private static async Task<string> GetDataFromServerAsync(){ string result; using(var client=new HttpClient()){ result=await client.GetStringAsync("http://example.com/api/data"); } return result; } ``` 这里展示了点击按钮触发事件处理器 (`FetchDataButton_Click`) 后发起 HTTP 请求的过程(`GetDataFromServerAsync`). 整个过程是非阻塞式的,因此即使请求正在处理期间,UI仍然保持活跃状态。 #### 最佳实践建议 为了充分利用 `async` 和 `await` 提供的功能,应当遵循一些最佳做法: - 避免不必要的同步异步转换; - 正确捕获和处理可能出现的各种异常情况; - 对多个独立的任务尽可能采取并行而非串行的方式来提高效率; - 利用 `IAsyncEnumerable<T>` 支持的数据流特性,以便更好地管理大量连续到达的信息片段[^4].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值