您的位置:首页 > 大数据 > 人工智能

await 和 Async 初探

2014-04-03 21:31 429 查看
在最近的项目中, 各种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);
}




 

 

 

 

 

 

 

 

从输出结果可以看到, 异步方法在遇到了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://www.cnblogs.com/mgen/archive/2012/03/12/2392677.html
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
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息