從版本5.0開始塘秦,C#引入了async/await的異步編程模式定踱,大大簡化了異步編程的難度筷狼,使我們擺脫了回調(diào)函數(shù)瓶籽、事件等傳統(tǒng)的方式,可以使用類似同步編程的方式進行異步編程埂材,這里通過一個小例子說明這種編程方式以及需要注意的地方塑顺。
異步編程的主要目的是當執(zhí)行到耗時較多的過程時,先啟動這個過程俏险,然后繼續(xù)執(zhí)行后續(xù)代碼严拒,當需要這個過程的返回的值時,再進行等待竖独。這些耗時的過程可能是從網(wǎng)上下載文件裤唠,或者從數(shù)據(jù)庫讀入初始化數(shù)據(jù)等等。使用async/await方式編程時预鬓,需要使用async聲明需要異步執(zhí)行的過程巧骚,比如:
async static Task<string> DoTask(int i)
{
Console.WriteLine("任務" + i+ "begin:" + Thread.CurrentThread.ManagedThreadId);
await Task.Run(() => Console.WriteLine("任務" + i+ ":" + Thread.CurrentThread.ManagedThreadId));
val = i.ToString();
Console.WriteLine("任務" +i+ "end:" + Thread.CurrentThread.ManagedThreadId);
return "任務"+i;
}
async返回的類型是Task或者Task<>,如果沒有返回格二,可以是void。需要注意的是:async聲明的函數(shù)或者方法中竣蹦,必須有使用await語句執(zhí)行的異步代碼顶猜,否則這個函數(shù)或過程會被同步執(zhí)行。反過來痘括,使用await語句調(diào)用異步執(zhí)行代碼的函數(shù)长窄,也必須聲明為async。在同步函數(shù)中可以直接調(diào)用異步函數(shù)纲菌,使用Task.Result獲取結(jié)果值挠日,比如:
string res=DoTask(10).Result;
下面的代碼啟動若干異步任務:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ZL.AsyncDemo
{
class Program
{
static string val;
static void Main(string[] args)
{
Run();
Console.ReadLine();
}
async static void Run()
{
var tasks = new List<Task<string>>();
for(var i = 0; i < 5; i++)
{
var task = DoTask(i);
tasks.Add(task);
}
Console.WriteLine("任務Main:" + Thread.CurrentThread.ManagedThreadId);
while (tasks.Any())
{
Task<string> finished = await Task<string>.WhenAny(tasks);
Console.WriteLine(finished.Result);
tasks.Remove(finished);
}
Console.WriteLine(val);
}
async static Task<string> DoTask(int i)
{
Console.WriteLine("任務" + i+ "begin:" + Thread.CurrentThread.ManagedThreadId);
await Task.Run(() => Console.WriteLine("任務" + i+ ":" + Thread.CurrentThread.ManagedThreadId));
val = i.ToString();
Console.WriteLine("任務" +i+ "end:" + Thread.CurrentThread.ManagedThreadId);
return "任務"+i;
}
}
}
從執(zhí)行結(jié)果看,這些任務不是在同一線程執(zhí)行的:
異步編程下需要注意的是訪問公用變量的問題翰舌,如果多個異步任務對同一公用變量進行修改的化嚣潜,結(jié)果可能不可預測,我們在這里定義了一個簡單的公用變量椅贱,在異步任務中對它進行賦值懂算,最后的結(jié)果是不可預測的只冻,上次執(zhí)行時結(jié)果是4,這次執(zhí)行就變成了2: