服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#异步编程详解

C#异步编程详解

2021-12-23 13:29东秦男人 C#

本文主要介绍异步编程中Task、Async和Await的基础知识。具有很好的参考价值,下面跟着小编一起来看下吧

前言

本节主要介绍异步编程中task、async和await的基础知识。

什么是异步?

异步处理不用阻塞当前线程来等待处理完成,而是允许后续操作,直至其它线程将处理完成,并回调通知此线程。

异步和多线程

相同点:避免调用线程阻塞,从而提高软件的可响应性。

不同点:

异步操作无须额外的线程负担,并且使用回调的方式进行处理,在设计良好的情况下,处理函数可以不必使用共享变量(即使无法完全不用,最起码可以减少 共享变量的数量),减少了死锁的可能。c#5.0 .net4.5 以后关键字async和await的使用,使得异步编程变得异常简单。

多线程中的处理程序依然是顺序执行,但是多线程的缺点也同样明显,线程的使用(滥用)会给系统带来上下文切换的额外负担。并且线程间的共享变量可能造成死锁的出现。

异步应用场景及原理

异步主要应用于io操作,数据库访问,磁盘操作,socket访问、http/tcp网络通信

原因:对于io操作并不需要cpu进行过多的计算,这些数据主要通过磁盘进行处理,如果进行同步通信无法结束,需要创建更多的线程资源,线程的数据上下文频繁的切换也是对资源的浪费,针对io操作不需要单独的分配一个线程来处理。

举例说明:

操作:服务器接收http请求对数据库进行操作然后返回

同步处理请求的线程会被阻塞,异步处理请求的线程不会阻塞。

C#异步编程详解

任务

在使用任务之前,针对线程的调用大多都用线程池提供的静态方法queueuserworkitem,但是这个函数有很多的限制,其中最大的问题就是没有内部机制可以让开发者知道操作在什么时候完成,也没有机制在操作完成时获取返回值,微软为了解决这个问题引入了任务的概念。

首先构造一个task<tresult>对象,并为tresult传递返回值,开始任务之后等待它并回去结果,示例代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static void main(string[] args)
   {
     console.writeline("开始进行计算");
     // threadpool.queueuserworkitem(sum, 10);
     task<int> task = new task<int>(sum, 100);
     task.start();
     //显示等待获取结果
     task.wait();
     //调用result时,等待返回结果
     console.writeline("程序结果为 sum = {0}",task.result);
     console.writeline("程序结束");
     console.readline();
   }
   public static int sum(object i)
   {
     var sum = 0;
     for (var j = 0; j <= (int) i; j++)
     {
       console.write("{0} + ",sum);
       sum += j;
     }
     console.writeline( " = {0}",sum);
     return sum;
   }

除了wait等待单个任务外,task还提供了等待多个任务,waitany和waitall,它阻止调用线程,直到数组中所有的task对象完成。

取消任务

任务的取消同样使用的是.net framework的标准取消操作模式,首先需要创建一个cancellationtokensource对象,然后在函数中加入参数cancellationtoken,将cancellationtokensource的token传递给方法,然后调用iscancellationrequested获取是否已经取消该值进行判断。

?
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
static void main(string[] args)
    {
      console.writeline("开始进行计算");
      // threadpool.queueuserworkitem(sum, 10);
      var ctx = new cancellationtokensource();
      var task = new task<int>(() => sum(ctx.token, 100000));
      task.start();
      //显示等待获取结果
      //task.wait(ctx.token);
      thread.sleep(1000);
      ctx.cancel();
      //调用result时,等待返回结果
      console.writeline("程序结果为 sum = {0}", task.result);
      console.writeline("程序结束");
      console.readline();
    }
    public static int sum(cancellationtoken cts, object i)
    {
      var sum = 0;   
      for (var j = 0; j <= (int)i; j++)
      {
        if (cts.iscancellationrequested) return sum;
        thread.sleep(50);
        console.write("{0} + ", sum);
        sum += j;
      }
      console.writeline(" = {0}", sum);
      return sum;
    }

任务完成后自动启动新任务

实际的开发应用中,经常出现一次任务完成后立刻启动另外一个任务,并且不能够使线程阻塞,在任务尚未完成时调用result会使程序阻塞,无法查看任务的执行进度,task提供了一个方法continuewith,它不会阻塞任何线程,当第一个任务完成时,会立即启动第二个任务。

?
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
static void main(string[] args)
    {
      console.writeline("开始进行计算");
      // threadpool.queueuserworkitem(sum, 10);
      var ctx = new cancellationtokensource();
      var task = new task<int>(() => sum(ctx.token, 100000));
      task.start();
      var cwt = task.continuewith(p =>
      {
        console.writeline("task result ={0} ",task.result);
      });
      //显示等待获取结果
      //task.wait(ctx.token);
      thread.sleep(1000);
      ctx.cancel();
      //调用result时,等待返回结果
      console.writeline("程序结果为 sum = {0}", task.result);
      console.writeline("程序结束");
      console.readline();
    }
    public static int sum(cancellationtoken cts, object i)
    {
      var sum = 0;   
      for (var j = 0; j <= (int)i; j++)
      {
        if (cts.iscancellationrequested) return sum;
        thread.sleep(50);
        console.write("{0} + ", sum);
        sum += j;
      }
      console.writeline(" = {0}", sum);
      return sum;
    }

async&await 简单使用

使用async&await的主要目的是方便进行异步操作,因为.net 4.0 以前进行异步操作时比较复杂的,主要是通过调用微软提供的异步回调方法进行编程,如果遇到需要自己实现的方法显得非常头疼,.net的各个版本都有自己主推的技术,像.net1.1中的委托,.net2.0中的泛型,.net3.0中的linq,.net4.0中的dynimac,.net4.5主推的就是异步编程,大家只需要了解task+异步函数就可以实现异步编程。

async:告诉clr这是一个异步函数。

await:将task<tresult>返回值的函数进行异步处理。

示例目的:获取网址js代码,并在界面显示。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private static async task<string> downloadstringwithretries(string uri)
    {
      using (var client = new httpclient())
      {
        // 第1 次重试前等1 秒,第2 次等2 秒,第3 次等4 秒。
        var nextdelay = timespan.fromseconds(1);
        for (int i = 0; i != 3; ++i)
        {
          try
          {
            return await client.getstringasync(uri);
          }
          catch
          {
          }
          await task.delay(nextdelay);
          nextdelay = nextdelay + nextdelay;
        }
        // 最后重试一次,以便让调用者知道出错信息。
        return await client.getstringasync(uri);
      }
    }
?
1
2
3
4
5
6
7
8
9
10
11
12
static void main(string[] args)
    {
      console.writeline("获取百度数据");
      executeasync();
      console.writeline("线程结束");
      console.readline();
    }
    public static async void executeasync()
    {
      string text = await downloadstringwithretries("http://wwww.baidu.com");
      console.writeline(text);
    }

运行结果发现,首先获取百度数据,线程结束,最后显示html代码,这是因为异步开启了新的线程,并不会造成线程阻塞。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持服务器之家!

原文链接:http://www.cnblogs.com/dongqinnanren/p/6278964.html

延伸 · 阅读

精彩推荐
  • C#SQLite在C#中的安装与操作技巧

    SQLite在C#中的安装与操作技巧

    SQLite,是一款轻型的数据库,用于本地的数据储存。其优点有很多,下面通过本文给大家介绍SQLite在C#中的安装与操作技巧,感兴趣的的朋友参考下吧...

    蓝曈魅11162022-01-20
  • C#如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    这篇文章主要给大家介绍了关于如何使用C#将Tensorflow训练的.pb文件用在生产环境的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴...

    bbird201811792022-03-05
  • C#C#微信公众号与订阅号接口开发示例代码

    C#微信公众号与订阅号接口开发示例代码

    这篇文章主要介绍了C#微信公众号与订阅号接口开发示例代码,结合实例形式简单分析了C#针对微信接口的调用与处理技巧,需要的朋友可以参考下...

    smartsmile20127762021-11-25
  • C#深入理解C#的数组

    深入理解C#的数组

    本篇文章主要介绍了C#的数组,数组是一种数据结构,详细的介绍了数组的声明和访问等,有兴趣的可以了解一下。...

    佳园9492021-12-10
  • C#利用C#实现网络爬虫

    利用C#实现网络爬虫

    这篇文章主要介绍了利用C#实现网络爬虫,完整的介绍了C#实现网络爬虫详细过程,感兴趣的小伙伴们可以参考一下...

    C#教程网11852021-11-16
  • C#三十分钟快速掌握C# 6.0知识点

    三十分钟快速掌握C# 6.0知识点

    这篇文章主要介绍了C# 6.0的相关知识点,文中介绍的非常详细,通过这篇文字可以让大家在三十分钟内快速的掌握C# 6.0,需要的朋友可以参考借鉴,下面来...

    雨夜潇湘8272021-12-28
  • C#C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    这篇文章主要介绍了C#设计模式之Strategy策略模式解决007大破密码危机问题,简单描述了策略模式的定义并结合加密解密算法实例分析了C#策略模式的具体使用...

    GhostRider10972022-01-21
  • C#VS2012 程序打包部署图文详解

    VS2012 程序打包部署图文详解

    VS2012虽然没有集成打包工具,但它为我们提供了下载的端口,需要我们手动安装一个插件InstallShield。网上有很多第三方的打包工具,但为什么偏要使用微软...

    张信秀7712021-12-15