Visual Studio Async CTP
寫程式難免會遇到回應延遲的問題,回應延遲的原因很多,有可能是一次擷取的資料量太大,也有可能是網路的問題,若是以單一執行緒的方式撰寫程式碼,使用者大概就只能等待,就連取消的機會都沒有。
在過去若要處理這種問題是很麻煩的,具有UI的應用程式通常是單一執行緒(STA),因此要直接跨執行緒存取資料是不可行的,以WPF為例通常必須設定一個static變數讓多個執行緒共同存取,控制項所提供的Dispatcher.BeginInvoke方式進行該變數的存取...
使用過VS11 Beta的使用者或許知道,在新版的.NET 4.5中提供了一種async…await的非同步方法,稱為Visual Studio Async Framework,如果在Visual Studio 2010中要執行這種非同步作業必須先安裝Visual Studio Async CTP...
安裝完畢後在"我的文件"中會產生一個Microsoft Visual Studio Async CTP的資料夾,其中包含了許多sample範例,使用時只要先將C:\Users\使用者\Documents\Microsoft Visual Studio Async CTP\Samples下的AsyncCtpLibrary.dll加入參考即可使用!
以一個下載RSS內容的小程式為例,我可能寫一個方法執行RSS的下載與剖析...
void LoadRss(string uri)
{
System.Net.WebRequest myRequest = System.Net.WebRequest.Create(uri);
System.Net.WebResponse myResponse = myRequest.GetResponse();
System.IO.Stream rssStream = myResponse.GetResponseStream();
System.Xml.XmlDocument rssDoc = new System.Xml.XmlDocument();
rssDoc.Load(rssStream);
System.Xml.XmlNodeList rssItems = rssDoc.SelectNodes("rss/channel/item");
ObservableCollection<RssItem> items = new ObservableCollection<RssItem>();
for (int i = 0; i < rssItems.Count; i++)
{
RssItem item = new RssItem();
System.Xml.XmlNode rssDetail;
rssDetail = rssItems.Item(i).SelectSingleNode("title");
if (rssDetail != null)
{
item.Title = rssDetail.InnerText;
}
else
{
item.Title = "";
}
rssDetail = rssItems.Item(i).SelectSingleNode("author");
item.Author = "";
if (rssDetail != null)
{
item.Author = rssDetail.InnerText;
}
else
{
item.Author = "";
}
rssDetail = rssItems.Item(i).SelectSingleNode("pubDate");
if (rssDetail != null)
{
try
{
item.PublishDate = Convert.ToDateTime(rssDetail.InnerText).ToString("yyyy年MM月dd日");
}
catch
{
item.PublishDate = DateTime.Today.ToLocalTime().ToShortDateString();
}
}
else
{
item.PublishDate = "";
}
rssDetail = rssItems.Item(i).SelectSingleNode("link");
if (rssDetail != null)
{
item.Link = rssDetail.InnerText;
}
else
{
item.Link = null;
}
items.Add(item);
}
listRss.ItemsSource = items;
}
這個程式基本上沒問題,但在第7行執行rssDXoc.Load()時可能會造成程式的瓶頸,因為載入RSS時是透過網際網路進行,因此在載入的同時會造成UI無法回應,如果我們改用Visual Studio Async 就可以解決這問題:
1.請把C:\Users\使用者\Documents\Microsoft Visual Studio Async CTP\Samples下的AsyncCtpLibrary.dll加入參考
2.加入System.Threading.Tasks命名空間
3.在原有的方法前加入async關鍵字
4.await TaskEx.Run(()=>要執行方法),如下第10行的委派方式
using System.Threading.Tasks;
.....
.....
async void LoadRssAsync(string uri)
{
System.Net.WebRequest myRequest = System.Net.WebRequest.Create(uri);
System.Net.WebResponse myResponse = myRequest.GetResponse();
System.IO.Stream rssStream = myResponse.GetResponseStream();
System.Xml.XmlDocument rssDoc = new System.Xml.XmlDocument();
await TaskEx.Run(()=>rssDoc.Load(rssStream));
System.Xml.XmlNodeList rssItems = rssDoc.SelectNodes("rss/channel/item");
ObservableCollection<RssItem> items = new ObservableCollection<RssItem>();
for (int i = 0; i < rssItems.Count; i++)
{
RssItem item = new RssItem();
System.Xml.XmlNode rssDetail;
rssDetail = rssItems.Item(i).SelectSingleNode("title");
if (rssDetail != null)
{
item.Title = rssDetail.InnerText;
}
else
{
item.Title = "";
}
rssDetail = rssItems.Item(i).SelectSingleNode("author");
item.Author = "";
if (rssDetail != null)
{
item.Author = rssDetail.InnerText;
}
else
{
item.Author = "";
}
rssDetail = rssItems.Item(i).SelectSingleNode("pubDate");
if (rssDetail != null)
{
try
{
item.PublishDate = Convert.ToDateTime(rssDetail.InnerText).ToString("yyyy年MM月dd日");
}
catch
{
item.PublishDate = DateTime.Today.ToLocalTime().ToShortDateString();
}
}
else
{
item.PublishDate = "";
}
rssDetail = rssItems.Item(i).SelectSingleNode("link");
if (rssDetail != null)
{
item.Link = rssDetail.InnerText;
}
else
{
item.Link = null;
}
items.Add(item);
}
listRss.ItemsSource = items;
}
要注意的是,async只能使用在無回傳型別的方法上,另外使用了Visual Studio Async 後,某些物件會增加擴充方法,例如:WebClient會有些以xxxTaskAsync的擴充方法,只要是回傳型別為Task或Task<T>的方法都可以使用await,若無就使用TaskEx.Run(delegate void)的方式即可!
AsyncWPF.rar(測試檔案下載)