c# async await

本篇博客来谈一下我对c#中的async和awaite关键字的理解。先来聊聊我在理解这个异步编程机制时的困惑吧。 
我看了使用 Async 和 Await 的异步编程(C# 和 Visual Basic)这篇文章后,感觉so easy,异步方法返回一个Task<TResult>对象,凭着我对Task类的“深入理解”,我就断定:当调用一个同步方法时,由于同步方法返回的是Task,.net自动就让这个task开始在后台线程中运行,然后这个同步方法直接返回,当调用await时,就等于调用了task的Wait()方法,会阻塞当前线程等待task返回结果。然后凭着我的理解,就写出了下面的代码


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main()
        {
            MyAsyncMethod();
            Console.ReadKey();
        }

        static async void MyAsyncMethod()
        {
            Console.WriteLine("call MyAsyncMethod.....");
            Task<int> calculateResult = CalculateAsync();
            Console.WriteLine("MyAsyncMethod was called.......");
            int result = await calculateResult;
            Console.WriteLine(string.Format("result is {0}", result));

        }

        static async Task<int> CalculateAsync()
        {
            int count = 5;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(5000);
                Console.WriteLine(string.Format("calculating step {0}",i));
            }
            Random random = new Random();
            return random.Next();
        }

    }
}

按照我上面的理解,第11行和第13行会被连续输出出来,但实际的输出确实

call MyAsyncMethod.....
calculating step 1
calculating step 2
calculating step 3
calculating step 4
calculating step 5
MyAsyncMethod was called.......
result is 900866582

也就是说,直到CalculateAsync()返回后,第13行代码才被执行!不是说好了使用async就是异步编程吗?这明明是逐步执行的!微软大骗子! 
再看看文档:


异步方法旨在成为非阻止操作。 异步方法中的 await 表达式在等待的任务正在运行时不会阻止当前线程。 相反,表达式在继续时注册方法的其余部分并将控件返回到异步方法的调用方。 
async 和 await 关键字不会导致创建其他线程。 因为异步方法不会在其自身线程上运行,因此它不需要多线程。 只有当方法处于活动状态时,该方法将在当前同步上下文中运行并使用线程上的时间。 可以使用 Task.Run 将占用大量 CPU 的工作移到后台线程,但是后台线程不会帮助正在等待结果的进程变为可用状态。 
对于异步编程而言,该基于异步的方法优于几乎每个用例中的现有方法。 具体而言,此方法比 BackgroundWorker 更适用于 IO 绑定的操作,因为此代码更简单且无需防止争用条件。 结合 Task.Run 使用时,异步编程比 BackgroundWorker 更适用于 CPU 绑定的操作,因为异步编程将运行代码的协调细节与 Task.Run 传输至线程池的工作区分开来。


好像看明白了些什么。async和await不会创建其它线程,异步方法需要将耗时的工作放到Task.Run中执行。好吧,修改下代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {

        static void Main()
        {
            MyAsyncMethod();
            string input = "";
            while ((input = Console.ReadLine()) != "q")
            {
                Console.WriteLine(@"your input is {input}");
            }
            Console.ReadKey();
        }

        static async void MyAsyncMethod()
        {
            Console.WriteLine("call MyAsyncMethod.....");
            Task<int> calculateResult = CalculateAsync();
            Console.WriteLine("MyAsyncMethod was called.......");
            int result = await calculateResult;
            Console.WriteLine(string.Format("result is {0}", result));

        }

        static async Task<int> CalculateAsync()
        {
            Console.WriteLine("calculation begin.....");
            int t = await Task.Run(() => Calculate());
            Console.WriteLine("calculation complete.....");
            return t;
        }

        static int Calculate()
        {
            // Compute total count of digits in strings.
            int count = 5;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(5000);
                Console.WriteLine(string.Format("calculating step {0}", i));
            }
            Random random = new Random();
            return random.Next();
        }

    }


}

计算的过程中还可以相应用户输入,比如:

call MyAsyncMethod.....
calculation begin.....
MyAsyncMethod was called.......
calculating step 1hello
your input is hello
calculating step 2下班了
your input is 下班了
calculating step 3calculating step 4world
your input is world
calculating step 5calculation complete.....result is 1805505488

上面的代码其实应该从下往上看。首先Calculate()是一个耗时的任务,CalculateAsync()是一个异步方法,当然,还是要使用Task.Run()的。MyAsyncMethod()方法来调用CalculateAsync()方法。在Main方法中,调用MyAsyncMethod()时会直接返回,不阻塞当前线程,因为当前线程还需要接受用户的输入。

最后,我把async和await理解为一种更方便地进行异步编程的机制,本身并不创建线程,但却实现了异步,非常简单。但是,有异步必然有多线程,一个线程不可能同时运行两个方法,只是我们以后在编写类的时候,可以通过Task.Run()来自己实现一些异步的方法,定义为async,这样可以简化UI线程的编程。


本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2025年4月    »
123456
78910111213
14151617181920
21222324252627
282930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864