返回顶部
首页 > 资讯 > 精选 >c#中异步编程的示例分析
  • 502
分享到

c#中异步编程的示例分析

2023-06-14 08:06:36 502人浏览 独家记忆
摘要

这篇文章给大家分享的是有关C#中异步编程的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、什么算异步?  广义来讲,两个工作流能同时进行就算异步,例如,CPU与外设之间的工作流就是异步的。在面向服务的系

这篇文章给大家分享的是有关C#中异步编程的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

一、什么算异步?

  广义来讲,两个工作流能同时进行就算异步,例如,CPU与外设之间的工作流就是异步的。在面向服务的系统中,各个子系统之间通信一般都是异步的,例如,订单系统与支付系统之间的通信是异步的,又如,在现实生活中,你去馆子吃饭,工作流是这样的,点菜->下单->做你的事->上菜->吃饭,这个也是异步的,具体来讲你和厨师之间是异步的,异步是如此重要,因外它代表者高效率(两者或两者以上的工作可以同时进行),但复杂,同步的世界简单,但效率极极低。

二、在编程中的异步

  在编程中,除了同步和异步这两个名词,还多了一个阻塞和非阻塞,其中,阻塞和非阻塞是针对线程的概念,那么同步和异步是针对谁呢?其实很多情况下同步和异步并没有具体针对某一事物,所以导致了针对同步阻塞、同步非阻塞、异步阻塞、异步非阻塞这几个概念的模糊不清。并且也确实没有清晰的边界,请看以下例子:

  public static void DoWorkA()  {    Thread thread = new Thread(() =>     {      Console.WriteLine("WorkA Done!");    });    thread.Start();  }  public static void DoWordB()  {    Thread thread = new Thread(() =>    {      Console.WriteLine("WorkB Done!");    });    thread.Start();  }  static void Main(string[] args)  {    DoWorkA();    DoWordB();  }

  假设运行该代码的CPU是单核单线程,那么请问?DoWorkA()、DoWorkB()这两个函数是异步的吗?因为CPU是单核,所以根本不能同时运行两个函数,那么从这个层次来讲,他们之间其实是同步的,但是,现实的情况是我们一般都认为他们之间是异步的,因为我们是从代码的执行顺序角度考虑的,而不是从CPU本身的工作流程考虑的。所以要分上下文考虑。再请看下面这个例子:

  static void Main(string[] args)  {    DoWorkA();    QueryDataBaseSync();//同步查询数据库    DoWorkB();  }

  从代码的执行顺序角度考虑,这三个函数执行就是同步的,但是,从CPU的角度来讲,数据库查询工作(另一台机器)和CPU计算工作是异步的,在下文中,没有做特别申明,则都是从代码的执行顺序角度来讨论同步和异步。
  再解释一下阻塞和非阻塞以及相关的知识:

  阻塞特指线程由运行状态转换到挂起状态,但CPU并不会阻塞,操作系统会切换另一个处于就绪状态的线程,并转换成运行状态。导致线程被阻塞的原因有很多,如:发生系统调用(应用程序调用系统api,如果调用成功,会发生从应用态->内核态->应用态的转换开销),但此时外部条件并没有满足,如从Socket内核缓冲区读数据,此时缓冲区还没有数据,则会导致操作系统挂起该线程,切换到另一个处于就绪态的线程然后给CPU执行,这是主动调用导致的,还有被动导致的,对于现在的分时操作系统,在一个线程时间片到了之后,会发生时钟中断信号,然后由操作系统预先写好的中断函数处理,再按一定策略(如线程优先级)切换至另一个线程执行,导致线程被动地从运行态转换成挂起状态。
  非阻塞一般指函数调用不会导致执行该函数的线程从运行态转换成挂起状态。

三、原始的异步编程模式之回调函数#

  在此之前,我们先稍微了解下图形界面的工作原理,GUI程序大概可以用以下伪代码表示:

While(GetMessage() != 'exit') //从线程消息队列中获取一个消息,线程消息队列由系统维护,例如鼠标移动事件,这个事件由操作系统捕捉,并投递到线程的消息队列中。{  msg = TranslateMessage();//转换消息格式  DispatherMessage(msg);//分发消息到相应的处理函数}

  其中DispatherMessage根据不同的消息类型,调用不同的消息处理函数,例如鼠标移动消息(MouseMove),此时消息处理函数可以根据MouseMove消息中的值,做相应的处理,例如调用绘图相关函数画出鼠标此刻的形状。
  一般来讲,我们称这个循环为消息循环(事件循环、EventLoop),编程模型称为消息驱动模型(事件驱动),在UI程序中,执行这部分代码的线程一般只有一个线程,称为UI线程,为什么是单线程,读者可以去思考。
  以上为背景知识。现在,我们思考,假如在UI线程中执行一个会导致UI线程被阻塞的操作,或者在UI线程执行一个纯CPU计算的工作,会发生什么样的结果?如果执行一个导致UI线程被阻塞的操作,那么这个消息循环就会被迫停止,导致相关的绘图消息不能被相应的消息处理函数处理,表现就是UI界面“假死”,直到UI线程被唤起。如果是纯CPU计算的工作,那么也会导致其他消息不能被及时处理,也会导致界面“假死”现象。如何处理这种情况?写异步代码。
  我们先用控制台程序模拟这个UI程序,后面以此为基础。

  public static string GetMessage()  {    return Console.ReadLine();  }  public static string TranslateMessage(string msg)  {    return msg;  }  public static void DispatherMessage(string msg)  {    switch (msg)    {      case "MOUSE_MOVE":        {          OnMOUSE_MOVE(msg);          break;        }      default:        break;    }  }  public static void OnMOUSE_MOVE(string msg)  {    Console.WriteLine("开始绘制鼠标形状");  }  static void Main(string[] args)  {    while(true)    {      string msg = GetMessage();      if (msg == "quit") return;      string m = TranslateMessage(msg);      DispatherMessage(m);    }  }

1、回调函数

  上面那个例子,一但外部有消息到来,根据不同的消息类型,调用不同的处理函数,如鼠标移动时产生MOUSE_DOWN消息,相应的消息处理函数就开始重新绘制鼠标的形状,这样一但你鼠标移动,就你会发现屏幕上的鼠标跟着移动了。
  现在假设我们增加一个消息处理函数,如OnMOUSE_DOWN,这个函数内部进行了一个阻塞的操作,如发起一个Http请求,在HTTP请求回复到来前,该UI程序会“假死”,我们编写异步代码来解决这个问题。

  public static int Http()  {    Thread.Sleep(1000);//模拟网络io延时    return 1;  }  public static void HttpAsync(Action<int> action,Action error)  {    //这里我们用另一个线程来实现异步IO,由于Http方法内部是通过Sleep来模拟网络IO延时的,这里也只能通过另一个线程来实现异步IO    //但记住,多线程是实现异步IO的一个手段而已,它不是必须的,后面会讲到如何通过一个线程来实现异步IO。    Thread thread = new Thread(() =>     {      try      {        int res = Http();        action(res);      }      catch      {        error();      }      });    thread.Start();  }  public static void OnMouse_DOWN(string msg)  {    HttpAsync(res =>     {      Console.WriteLine("请求成功!");      //使用该结果做一些工作    }, () =>     {      Console.WriteLine("请求发生错误!");    });  }

  此时界面不再“假死”了,我们看下代码可读性,感觉还行,但是,如果再在回调函数里面再发起类似的异步请求呢?(有人可能有疑问,为什么还需要发起异步请求,我发同步请求不行吗?这都是在另一个线程里了。是的,在这个例子里是没问题的,但真实情况是,执行回调函数的代码,一般都会在UI线程,因为取得结果后需要更新相关UI组件上的界面,例如文字,而更新界面的操作都是放在UI线程里的,如何把回调函数放到UI线程上执行,这里不做讨论,在.net中,这跟同步上下文(Synchronization context)有关,后面会讲到),那么代码会变成这样

  public static void OnMouse_DOWN(string msg)  {    HttpAsync(res =>     {      Console.WriteLine("请求成功!");      //使用该结果做一些工作      HttpAsync(r1 =>       {        //使用该结果做一些工作        HttpAsync(r2 =>         {          //使用该结果做一些工作        }, () =>         {        });      }, () =>       {      });    }, () =>     {      Console.WriteLine("请求发生错误!");    });  }

  写过js的同学可能很清楚,这叫做“回调地狱”,如何解决这个问题?JS中有Promise,而C#中有Task,我们先用Task来写这一段代码,然后自己实现一个与Task功能差不多的简单的类库。

  public static Task<int> HttpAsync()  {    return Task.Run(() =>     {      return Http();    });  }  public static void OnMouse_DOWN(string msg)  {    HttpAsync()      .ContinueWith(t =>       {        if(t.Status == TaskStatus.Faulted)        {        }else if(t.Status == TaskStatus.RanToCompletion)        {          //做一些工作        }      })      .ContinueWith(t =>       {        if (t.Status == TaskStatus.Faulted)        {        }        else if (t.Status == TaskStatus.RanToCompletion)        {          //做一些工作        }      })      .ContinueWith(t =>       {        if (t.Status == TaskStatus.Faulted)        {        }        else if (t.Status == TaskStatus.RanToCompletion)        {          //做一些工作        }      });  }

  是不是感觉清爽了许多?这是编写异步代码的第一个跃进。下篇将会介绍,如何自己实现一个简单的Task。后面还会提到C#中async/await的本质作用,async/await是怎么跟Task联系起来的,怎么把自己写的Task库与async/await连结起来,以及一个线程如何实现异步IO。

感谢各位的阅读!关于“c#中异步编程的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

--结束END--

本文标题: c#中异步编程的示例分析

本文链接: https://lsjlt.com/news/269379.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • c#中异步编程的示例分析
    这篇文章给大家分享的是有关c#中异步编程的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、什么算异步?  广义来讲,两个工作流能同时进行就算异步,例如,CPU与外设之间的工作流就是异步的。在面向服务的系...
    99+
    2023-06-14
  • C#异步编程的示例分析
    小编给大家分享一下C#异步编程的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!异步编程在处理并发方面被使用的越来越多,之所以说上面一句话,是为了区分多线程...
    99+
    2023-06-17
  • Promise中异步编程的示例分析
    这篇文章主要介绍Promise中异步编程的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!实例如下所示://1.解决异步回调问题 //1.1 如何同步异步请求 //如...
    99+
    2024-04-02
  • JavaScript中异步编程的示例分析
    这篇文章给大家分享的是有关JavaScript中异步编程的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。目的提升开发效率,编写易维护的代码引子问题请求时候为什么页面卡死??$.ajax({ &n...
    99+
    2023-06-15
  • Node.js中的异步编程的示例分析
    Node.js中的异步编程的示例分析,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。异步编程概述曾经的单线程模型在...
    99+
    2024-04-02
  • js异步编程的示例分析
    这篇文章主要为大家展示了“js异步编程的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“js异步编程的示例分析”这篇文章吧。异步回调是js的一大特性,理解...
    99+
    2024-04-02
  • python中asyncio异步编程的示例分析
    这篇文章将为大家详细讲解有关python中asyncio异步编程的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1.   想学asyncio,得先了解协程携程的意义:计算型的操...
    99+
    2023-06-14
  • C#中异步多线程的示例分析
    这篇文章主要介绍C#中异步多线程的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!进程、线程1. 进程首先了解,什么是线程 即一个应用程序运行时,占用资源的综合是一个进程。Windows 任务管理器里面可以看到...
    99+
    2023-06-25
  • C#异步多线程中Thread的示例分析
    这篇文章给大家分享的是有关C#异步多线程中Thread的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Thread API这里对 Thread 的一些常用 API 进行介绍,使用一些案例进行说明。由于 T...
    99+
    2023-06-25
  • C#异步通信的示例分析
    这篇文章主要为大家展示了“C#异步通信的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C#异步通信的示例分析”这篇文章吧。C#异步通信概念及应用的认识首先让我们来看看:在网络编程中运用S...
    99+
    2023-06-17
  • JavaScript中异步的示例分析
    这篇文章将为大家详细讲解有关JavaScript中异步的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、异步解决方案的进化史JavaScript的异步操作一直是...
    99+
    2024-04-02
  • c++中异常的示例分析
    这篇文章主要介绍了c++中异常的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、什么是异常处理一句话:异常处理就是处理程序中的错误。二、为什么需要异常处理,异常处理...
    99+
    2023-06-15
  • JS中异步和单线程的示例分析
    这篇文章主要介绍了JS中异步和单线程的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。单线程但是我们在开发中,遇到请求网络,或者定时任务的时候,如果等待网络请求结束或者...
    99+
    2023-06-15
  • Ajax中同步和异步的示例分析
    小编给大家分享一下Ajax中同步和异步的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!通过ajax向后台发送和接收数据时...
    99+
    2024-04-02
  • Nodejs中异步I/O的示例分析
    小编给大家分享一下Nodejs中异步I/O的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!“异步”这个名词其实在Node之前就已经诞生了。但是在绝大多数高...
    99+
    2023-06-14
  • Springboot中异步任务的示例分析
    小编给大家分享一下Springboot中异步任务的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!异步任务启动类@MapperScan("com....
    99+
    2023-06-17
  • React中setState同步和异步的示例分析
    这篇文章主要介绍React中setState同步和异步的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完! React起源于Facebook的内部项目。React的出现是革命性的创新,React的是一个...
    99+
    2023-06-15
  • C++模板编程的示例分析
    这篇文章主要为大家展示了“C++模板编程的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C++模板编程的示例分析”这篇文章吧。模板初阶泛型编程在计算机程序设计领域,为了避免因数据类型的不...
    99+
    2023-06-25
  • Node.js异步编程实例代码分析
    这篇文章主要介绍了Node.js异步编程实例代码分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Node.js异步编程实例代码分析文章都会有所收获,下面我们一起来看看吧。异步编程案例一function&nbs...
    99+
    2023-07-04
  • C#多线程中线程同步的示例分析
    这篇文章将为大家详细讲解有关C#多线程中线程同步的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、前言我们先来看下面一个例子:using System;using Syste...
    99+
    2023-06-29
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作