在最近的项目中, 各种await关键字到处乱串,所以很有必要来了解下await和async 异步编程。

首先来了解些基本的概念:

1. 构建一个异步函数:

    1) 申明时加入async 或Async 修饰符

    2)返回值定义为 Task (普通函数中的void) 或 Task<T>(普通函数中的返回值)

    3) 按约定,函数名以Async结尾     比如: async Task MethodName();  async Task<bool> Method Name();

2. 在异步函数中,需要包含await关键字

3. await 关键字:

函数遇到await关键字后会挂起当前函数,然后返回上一级调用函数, 直到await 后面的语句返回task or Task<T>, 然后继续await下面的语句。

http://msdn.microsoft.com/zh-cn/library/hh156528.aspx

 

接下来的几个典型场景,让我逐步了解这2个关键字的特性

1. 典型的异步调用

static void Main(string[] args)
        {
            Console.WriteLine("Thread {0} Main Function Starts", Thread.CurrentThread.ManagedThreadId);

            AsyncClass asyncClass = new AsyncClass();
            asyncClass.testSimpleAsync();

            Console.WriteLine("Thread {0} Main Function Ends \n", Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(Timeout.Infinite);
        }

 

/// 由于Main函数不能声明为异步方法,所以新建一个异步方法来调用目标异步方法
            /// </summary>
            public async Task testSimpleAsync()
            {
                Console.WriteLine("\nThread {0}   testSimpleAsync starts", Thread.CurrentThread.ManagedThreadId);
                Task displayCall = DisplayAsync();
                Thread.Sleep(2);
                await displayCall;
                Console.WriteLine("Thread {0}  testSimpleAsync complete \n", Thread.CurrentThread.ManagedThreadId);
            }
/// <summary>
            /// 目标异步方法
            /// </summary>
            /// <returns></returns>
            private async Task DisplayAsync()
            {
                Console.WriteLine("\nThread {0} DisplayAsync starts", Thread.CurrentThread.ManagedThreadId);
                await Task.Delay(10);
                Console.WriteLine("Thread {0} DisplayAsync ends \n", Thread.CurrentThread.ManagedThreadId);
            }

vite async不兼容ios_vite async不兼容ios

 

 

 

 

 

 

 

 

从输出结果可以看到, 异步方法在遇到了await关键字后, 会立即返回被调用函数(如在DisplayAsync()中遇到await, 立即返回被调用testSimpleAsync函数并执行testSimpleAysnc后面的语句),然后等待await后面的语句返回并执行后面的操作。

注意到这里的DispalyAsync ends 和 testSimpleAsync complete 在不同的线程上,但这不是由于await关键字创建新的线程给await后面的语句,而是由于后面的语句本身会产生新的线程。 在这里,是Task.Delay(10);产生了新的线程, 参考:http://social.technet.microsoft.com/wiki/contents/articles/21177.visual-c-thread-sleep-vs-task-delay.aspx 

 

2. 让多个任务并发

public async void testConcurrencyCall_NewThreadAsync()
            {

                Console.WriteLine("testConcurrencyCall_NewThread Start");

                List<Task> lstTasks = new List<Task>();

                for (int i = 2; i <= 5; i++)
                {
                    Console.WriteLine("{0}:     testConcurrencyCall_NewThread before starting new task      cycle-{1}", Thread.CurrentThread.ManagedThreadId, i);
                    Task task = Task.Factory.StartNew(() => DisplayAsync(i));  //DisplayAsync will run immediately at new thread.
                    Console.WriteLine("{0}:     testConcurrencyCall_NewThread after starting new task       cycle-{1}", Thread.CurrentThread.ManagedThreadId, i);
                    lstTasks.Add(task);

                }
                await Task.WhenAll(lstTasks);//Wait for all tasks complete.
                Console.WriteLine("testConcurrencyCall_NewThread complete \n");
            }

            private async Task DisplayAsync(int i)
            {
                Console.WriteLine("{0}:     {1}:        cycle-{2}", Thread.CurrentThread.ManagedThreadId, "DisplayAsync starts", i);
                await Task.Delay(3000);
                Console.WriteLine("{0}:     {1}:        cycle-{2}", Thread.CurrentThread.ManagedThreadId, "DisplayAsync end", i);

            }

Task.Factory.StartNew会开启一个新的线程跑异步方法, 在循环中将所有DisplayAsync触发完成, Task.WhenAll等待所有方法完成在继续下个操作。

 这里提下Task.Run() 和Task.Factory.StartNew, 实际上都是开启一个新的线程跑方法, 只是 Task.Factory.StartNew的可选参数更多,Task.Run()用的是默认参数:http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx

上面的这个方式,实际上用System.Threading.Tasks.Parallel.For也可以完成同样的效果。

 

3. 把一个异步方法转化成同步方法:

 #1

public void convertAsSync()
            {
                Task task = Task.Run(() => DisplayAsync());
                task.Wait();
            }

 #2

public void convertAsSync()
            {
                Task task = DisplayAsync();
                task.Wait();
            }

Task.wait会等待Task完成后再继续后面的语句,可以把异步的方法DisplayAsync()转换成同步方法,不同的,

#1会开启一个新的线程跑整个DisplayAsync()

#2会在同个线程中调用DisplayAsync.

这就是几个基本Await和Async使用,要用好这2个关键字,要更加深入的了解Task和Task相关的方法(Run. WhenAll,AnyAll, ContinueWith等), 以后有时间再研究下。

 

参考链接:

http://msdn.microsoft.com/zh-cn/library/hh873191.aspx

http://msdn.microsoft.com/zh-cn/library/hh191443.aspx

http://tomasp.net/blog/csharp-async-gotchas.aspx/

http://www.codeproject.com/Articles/127291/C-vNext-New-Asynchronous-Pattern

http://msdn.microsoft.com/zh-cn/library/hh873191.aspx