广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >c# 异步编程入门
  • 741
分享到

c# 异步编程入门

2024-04-02 19:04:59 741人浏览 独家记忆
摘要

目录一、什么算异步? 二、在编程中的异步 三、原始的异步编程模式之回调函数# 1、回调函数 一、什么算异步?   广义来讲,两个工作流能同时进行就算异步,例

一、什么算异步?

  广义来讲,两个工作流能同时进行就算异步,例如,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# 异步编程入门的详细内容,更多关于c# 异步编程的资料请关注编程网其它相关文章!

--结束END--

本文标题: c# 异步编程入门

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

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

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • c# 异步编程入门
    目录一、什么算异步? 二、在编程中的异步 三、原始的异步编程模式之回调函数# 1、回调函数 一、什么算异步?   广义来讲,两个工作流能同时进行就算异步,例...
    99+
    2022-11-12
  • PHP入门指南:异步编程
    PHP作为一门流行的脚本语言,一直以来都是Web开发的主流语言之一。在Web开发中,异步编程被越来越多地应用于网络爬虫、实时聊天、长轮询等高性能场景。本文将介绍PHP异步编程的相关知识,以便读者掌握异步编程基础,提高Web应用性能。一、异步...
    99+
    2023-05-20
    PHP 异步编程 入门指南
  • C# 异步多线程入门基础
    目录进程、线程1. 进程 2. 线程 分时、分片同步、异步异步、多线程异步多线程效率多线程无序性扩展异步多线程版本下一篇:C# 异步多线程入门到精通之Thread篇 进程、线程 1....
    99+
    2022-11-12
  • C++元编程语言初步入门详解
    目录模板泛型初步函数模板友元模板参数元编程的基本概念可变参数模板模板 由于模板元编程需要以面向对象为基础,所以如有疑问之处可以先补充一点C++面向对象的知识: C++面向对象这一篇就...
    99+
    2022-11-12
  • C#异步编程由浅入深(一)
    目录一、什么算异步?二、在编程中的异步三、原始的异步编程模式之回调函数1、回调函数一、什么算异步? 广义来讲,两个工作流能同时进行就算异步,例如,CPU与外设之间的工作流就是异步的。...
    99+
    2022-11-13
  • 大数据处理:Python 异步编程入门教程
    在当今的大数据时代,数据处理已经成为了每个企业必不可少的一项工作。如何快速高效地处理海量数据,成为了每个数据工程师必须面对的挑战。Python作为一门高效的编程语言,已经成为了许多数据工程师的首选。而异步编程作为Python中处理大数据的...
    99+
    2023-09-29
    教程 大数据 异步编程
  • 编程算法入门:Go和npm的异步编程技巧
    在现代编程中,异步编程已经成为了一种非常重要的技巧。它可以让我们的程序更加高效,更加灵活。在本文中,我们将介绍Go和npm中的异步编程技巧。 Go中的异步编程 Go是一种非常流行的编程语言,它提供了丰富的异步编程功能。其中最重要的是Gor...
    99+
    2023-09-24
    npm 异步编程 编程算法
  • C# 异步多线程入门到精通之Thread篇
    上一篇:C# 异步多线程入门基础 下一篇:C# 异步多线程入门到精通之ThreadPool篇 Thread API 这里对 Thread 的一些常用 API 进行介绍,使用一些案例进...
    99+
    2022-11-12
  • C#异步多线程入门到精通之ThreadPool篇
    上一篇:C# 异步多线程入门到精通之Thread篇 下一篇:异步多线程之入Task,待更新 启动线程池线程 ThreadPool 提供的 API 相对于 Thread 是比较少的,在...
    99+
    2022-11-12
  • PHP Laravel 异步编程入门教程,你准备好了吗?
    随着互联网的发展,我们对于网站的需求越来越高。网站的访问速度、流畅度等问题已经成为制约用户体验的关键因素。在这样的背景下,异步编程技术逐渐成为了开发者们的关注焦点。 异步编程技术不仅可以提高网站的响应速度,还可以提高并发处理能力,节省服务...
    99+
    2023-08-26
    laravel 教程 异步编程
  • PHP Laravel 异步编程入门指南,让你快速上手!
    随着互联网技术的发展,越来越多的应用程序需要处理大量的并发请求,传统的同步处理方式已经无法满足需求。异步编程成为了解决这个问题的重要手段之一。PHP Laravel 作为一个流行的 Web 开发框架,也提供了一些异步编程的解决方案。本篇文...
    99+
    2023-08-26
    laravel 教程 异步编程
  • C#异步编程由浅入深(三)之详解Awaiter
      上一篇末尾提到了Awaiter这个类型,上一篇说了,能await的对象,必须包含GetAwaiter()方法,不清楚的朋友可以看上篇文章。那么,Awaiter...
    99+
    2022-11-13
  • c# 异步编程基础讲解
    目录Task 和 Task<T>I/O 受限异步操作CPU 受限异步操作异步编程模式现代应用程序广泛使用文件和网络 I/O。I/O 相关 API 传统上默认是阻塞的,导致...
    99+
    2022-11-12
  • C++BoostSpirit入门教程
    目录一、Boost.Spirit库介绍二、boost::spirit::qi::parse()解析格式三、解析器一、Boost.Spirit库介绍 本章介绍库 Boost.Spiri...
    99+
    2022-11-16
    C++ Boost Spirit C++ Spirit
  • C#异步编程由浅入深(二)之Async/Await的使用
      考虑到直接讲实现一个类Task库思维有点跳跃,所以本节主要讲解Async/Await的本质作用(解决了什么问题),以及Async/Await的工作原理。实现一...
    99+
    2022-11-13
  • Python 异步编程入门指南:掌握 load 函数的使用方法
    随着互联网的发展,越来越多的人开始关注异步编程。Python 作为一门流行的编程语言,也提供了一些强大的异步编程工具,例如 asyncio 库。在异步编程中,load 函数是一个非常重要的函数,它可以帮助我们实现高效的异步操作。本文将介绍...
    99+
    2023-10-17
    异步编程 编程算法 load
  • 快速入门Go语言异步编程:使用IDE的函数技巧。
    快速入门Go语言异步编程:使用IDE的函数技巧 Go语言是一种高效的编程语言,具有强大的并发支持和高性能的特点,因此被广泛应用于分布式系统、云计算等领域。其中异步编程是Go语言的一大特色,可以大大提高程序的并发处理能力。本文将介绍如何使用I...
    99+
    2023-11-11
    异步编程 ide 函数
  • 从入门到精通:掌握 PHP Windows 异步编程框架的技巧
    在如今的互联网时代,PHP是非常流行的一种编程语言,尤其是在Web开发方面,PHP的应用非常广泛。而在PHP的开发过程中,异步编程框架是一个非常重要的技术,可以大大提高程序的性能和效率。本文将从入门到精通的角度,为大家介绍掌握PHP Win...
    99+
    2023-08-16
    windows 异步编程 框架
  • C#异步编程的三种模式
    使用异步编程,方法调用是在后台运行(通常在线程和任务的帮助下),并且不会阻塞调用线程。异步编程有三种模式:异步模式,基于事件的异步模式和基于任务的异步模式(TAP)。 一.异步模式 ...
    99+
    2022-11-13
  • C#异步编程之async/await详解
    目录概述C#异步编程用法async/await和Task简介asyncawaitTask其他实现原理剖析实现原理示例概述 异步这个概念在不同语境下有不同的解释,比如在一个单核CPU里...
    99+
    2023-03-11
    C#异步编程async await C#异步编程 C# async await
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作