幾個(gè)月前做的一個(gè)軟件里想添加一個(gè)天氣預(yù)報(bào)功能, 也就是利用了一下Google Weather的接口: http://www.google.com/ig/api?hl=zh-cn&weather=某某市,某某省 , 效果也達(dá)到了.
不忘書(shū)中所講: 耗時(shí)操作, 且非計(jì)算密集型任務(wù), 最好使用異步方法. 根據(jù)Anders Hejlsberg的視頻中演示的那樣, 我寫(xiě)出下面一段代碼, 也是很多人拿來(lái)演示異步的經(jīng)典寫(xiě)法:
00
public void GetWeather(string city, string province)
01
{
02
var myRequest = (HttpWebRequest)WebRequest.Create("http://www.google.com/ig/api?hl=zh-cn&weather=" + city + "," + province);
03
myRequest.BeginGetResponse(delegate(IAsyncResult ar)
04
{
05
var response = myRequest.EndGetResponse(ar);
06
StreamReader weatherStream = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("gb2312"));
07
string weatherString = weatherStream.ReadToEnd();
08
weatherStream.Dispose();
09
}, null);
10
}
就是這樣的一個(gè)所謂異步的方法, 運(yùn)行一下, 最短的時(shí)候花了3秒多才獲取到了weatherString, 很多時(shí)候甚至花了10秒多. 我就眼巴巴的看著程序在假死(Not Responding), 一邊看著我的代碼, 我不是異步了么? 異步不是就是為了避免程序假死的么? 目前來(lái)看程序似乎并沒(méi)有異步.
于是開(kāi)始找原因...也請(qǐng)教了不少人...也得到了一些可能的原因:
嫌疑1: 程序運(yùn)行的時(shí)候第一步在尋找DNS將google.com對(duì)應(yīng)到某個(gè)具體的IP地址, 這項(xiàng)任務(wù)花費(fèi)了不少時(shí)間.
事實(shí)上我Ping了google.com之后, 把google.com換成IP地址, 運(yùn)行程序, 并沒(méi)有發(fā)現(xiàn)有什么效果...
嫌疑2: 程序只實(shí)現(xiàn)了BeginGetResponse的異步, 還有GetResponseStream等等之類(lèi)的方法并沒(méi)有異步.
但把GetResponseStream改成BeginGetResponseStream之后, 也沒(méi)有任何改觀.
嫌疑3: 系統(tǒng)在給這個(gè)WebRequest分配資源, 諸如WebRequest類(lèi), StreamReader之類(lèi)的還算"比較大"的對(duì)象花費(fèi)了時(shí)間.
想一想這些應(yīng)該都是在高速緩存上進(jìn)行的, 不至于要花3秒, 10多秒吧?
這個(gè)問(wèn)題還真不太好描述, 事實(shí)上后來(lái)做了一系列的測(cè)試, 測(cè)試發(fā)現(xiàn)只有第一次發(fā)出WebRequest看似不是異步的. 接下來(lái)繼續(xù)嘗試幾次發(fā)出WebRequest, 到獲得Response的時(shí)間就非常非常短. 為了找出究竟在哪個(gè)環(huán)節(jié)耗時(shí)比較厲害, 我寫(xiě)了一個(gè)控制臺(tái)程序來(lái)測(cè)試, 測(cè)試中我用了一個(gè)for循環(huán), 連續(xù)發(fā)出5次同樣的WebRequest, 測(cè)試結(jié)果如下:
可以發(fā)現(xiàn)程序在第一次初始化WebRequest和第一次從發(fā)出請(qǐng)求到獲得響應(yīng)消耗的時(shí)間最多! 昨天發(fā)現(xiàn)原來(lái)是代理(Proxy)的問(wèn)題! MSDN中關(guān)于HttpWebRequest.Proxy屬性是這樣描述的:
本地計(jì)算機(jī)或應(yīng)用程序配置文件可能指定使用默認(rèn)代理。 如果指定了 Proxy 屬性,則 Proxy 屬性中的代理設(shè)置會(huì)重寫(xiě)本地計(jì)算機(jī)或應(yīng)用程序配置文件,并且 HttpWebRequest 實(shí)例將實(shí)用指定的代理設(shè)置。 如果配置文件中未指定代理并且未指定 Proxy 屬性,則 HttpWebRequest 類(lèi)使用從本地計(jì)算機(jī)上的 Internet Explorer 中繼承的代理設(shè)置。 如果 Internet Explorer 中沒(méi)有代理設(shè)置,請(qǐng)求會(huì)直接發(fā)送到服務(wù)器。
回到遇到的問(wèn)題, 程序并沒(méi)有指定代理, 第一次運(yùn)行的時(shí)候, 程序會(huì)尋找IE中的代理, 如果沒(méi)有找到才會(huì)去直接訪問(wèn)服務(wù)器, 這中間花費(fèi)了不少時(shí)間. 要解決這個(gè)問(wèn)題, 請(qǐng)?jiān)诖a中加上這么一行:
xxRequest.Proxy = null;