异步编程(async 和 await)

1.概念

异步编程是一项关键技术,可以直接处理多个核心上的I/O阻塞和并发操作

2.使用场景

对于存在IO密集型(例如从网路请求数据、访问数据库和写入到文件系统)和CPU密集型(例如大量的计算)的任务可以选择异步编程

3.异步编程针对于IO密集型任务的优点

针对于服务器端和客户端分别描述

服务器端:

    a:由于没有专门的用于阻止未完成任务的线程,因此服务器线程可以服务更多的Web请求。   

    b:现模拟假设一个场景,有两台服务器,都只有5个线程可用于服务请求,一台运行异步代码,一台不运行异步代码。

    假设这两台服务器都接收6个并发请求,每个请求执行一个I/O操作,未运行异步代码的服务器必须对6个请求排队直到5个线程中的一个完成了I/O密集型工作并编写了响应。假如此时收到了20个请求,由于队列太长,服务器可能开始变慢。运行有异步代码的服务器也需要对6个请求排队,但由于使用了async 和 await,I/O密集型工作开始时,每个线程都会得到释放,无需等到工作结束,收到第20个请求时,传入请求队列将变得很小(如果其中还有请求的话),且服务器不会变慢。 

     c:由于I/O操作在CPU上几乎没有耗时,所以将整个CPU线程专用于执行几乎没有任何作用的工作将是一种资源浪费。

客户端:

     a:使用了async和await对于客户端应用带来的最大好处在于提高了响应能力。例如:手机游戏等应用,在涉及IO时尽可能少的影响UI线程,这点至关重要。

4.异步编程针对于CPU密集型任务的优点

服务器端:

   使用异步编程可以开启另外一个线程来处理这一个CPU密集型的任务,另外一个线程就有可能是多核CPU情况下的另一个核,从而充分的利用了多核CPU的优势。

客户端:

   此优点和上述针对IO密集型任务的一致

5.I/O密集型和CPU密集型任务的异步编程模型

大多数场景下:

对于I/O密集型,await 异步方法(aysnc修饰的返回Task或者Task<T>)

对于CPU密集型,await 异步方法(Task.Run()一个新的任务)

6.示例代码展示

I/O密集型:

private static readonly HttpClient s_client = new HttpClient(); 

static async Task Main(string[] args)
{
     Console.WriteLine("ThreadId:"+Thread.CurrentThread.ManagedThreadId);
     var result = await GetHtmlAsync();
     Console.WriteLine("内容长度:"+result.Length);
     Console.WriteLine("ThreadId:" + Thread.CurrentThread.ManagedThreadId);
}

static Task<string> GetHtmlAsync()
{
     Console.WriteLine("ThreadId:" + Thread.CurrentThread.ManagedThreadId);
     var uri = new Uri("https://www.dotnetfoundation.org");
     return s_client.GetStringAsync(uri);
}

 输出的结果是:

      

Main方法执行到await之后,开始调用GetHtmlAsync方法,这个过程仍然是由线程1在进行,当代码执行到s_client.GetStringAsync(uri)之后,此时会将工作委托给操作系统,线程1此时可以被调度去处理其余的任务,s_client.GetStringAsync(uri)完成之后,此时是从CPU调度出新的空闲线程来执行接下来的任务,也就是输出的线程7

使用await关键字不会开启新的线程,只有await后面跟的是类似于GetStringAsync等内置的.NET异步方法,或者自定义的异步方法(方法内部使用了Task.Run或者Task.Factory.StartNew开启了新的Task)  

CPU密集型:

static async Task Main(string[] args)
{
    Console.WriteLine("Main1:" + Thread.CurrentThread.ManagedThreadId);
    Task<long> task = Task.Run(() => BigComputeTest());
    long result = 0;
    int sum = 0;
    for (int i = 0; i < 10000; i++)
    {
        sum += i;
    }
    Console.WriteLine("Main2:" + Thread.CurrentThread.ManagedThreadId);
    result = await task;
    Console.WriteLine($"sum:{sum},result:{result}");
    Console.WriteLine("Main3:" + Thread.CurrentThread.ManagedThreadId);
}

static long BigComputeTest()
{
    Console.WriteLine("BigComputeTest1:" + Thread.CurrentThread.ManagedThreadId);
    long sum = 0;
    for (long i = 0; i < 100000000; i++)
    {
        sum += i;
    }
    return sum;
}

输出的结果是:

Main方法执行到Task.Run(() => BigComputeTest())时,开启一个新的线程去执行BigComputeTest方法,于此同时可以去执行Main方法中的任务,从计算量上分析,Main方法中的计算会先执行完,因为先输出"Main2:1",执行到await Task时Main方法会等待BigComputeTest执行完,线程1会空闲下来去处理其它的事情,直到BigComputeTest()执行完,Main方法中的余下代码会继续执行,此时执行的话是由执行BigComputeTest方法的线程4来进行的。

结尾

本篇博客中一些描述如有错误,请大家指正

   

                                                                                                        

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
异步编程是一种编程模式,它允许程序在等待某些操作完成时继续执行其他任务,而不是阻塞整个程序的执行。Python中的异步编程可以使用`async`和`await`关键字来实现。 `async`关键字用于定义一个异步函数,这个函数可以使用`await`关键字来挂起自身的执行,等待其他的异步操作完成后再继续执行。 下面是一个简单的例子,展示了如何使用`async`和`await`来实现异步编程: ```python import asyncio async def async_task(): print("异步任务开始") await asyncio.sleep(1) # 模拟耗时操作 print("异步任务结束") async def main(): print("主程序开始") await asyncio.gather(async_task(), async_task()) # 并发执行两个异步任务 print("主程序结束") asyncio.run(main()) ``` 在上面的例子中,我们定义了一个异步函数`async_task()`,它会打印一些信息,然后使用`await asyncio.sleep(1)`来模拟一个耗时操作。然后我们定义了另一个异步函数`main()`,它会并发地执行两个`async_task()`函数。最后,在`asyncio.run(main())`中运行主程序。 通过运行上面的代码,你会看到输出的顺序是"主程序开始" -> "异步任务开始" -> "异步任务开始" -> "异步任务结束" -> "异步任务结束" -> "主程序结束"。可以看到,在执行异步任务时,主程序不会被阻塞,而是继续执行其他任务。 异步编程在处理I/O密集型任务时特别有用,因为它可以充分利用等待I/O操作完成的时间,同时执行其他任务,提高程序的性能和响应性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值