技术分享 - Windows Phone的异步模型
为了不阻塞UI,在windows的多线程上完全去掉了同步的模型,全部使用异步模型来处理请求。这样带来的好处是UI不会被卡死,能够一直响应用户的响应,将比较耗时的操作丢给后台线程处理,并且能避开线程同步的麻烦。
但这样一来,写出来的代码也比较难看,还可能涉及到数据共享的问题。
我相信如果你的应用涉及到HttpRequest的话那么一定会遇到我说的情况。
欢迎大家一起讨论你的思路。
以下是几种我常用的异步请求代码的模型
1、使用匿名函数,有时候为了节约会使用lamda表达式
2、事件模式,通过订阅请求完成事件
3、Async CTP
第一种方式的代码如下:
private string Reqest()
{
string resultString = string.Empty;
HttpWebRequest request = HttpWebRequest.CreateHttp("http://www.google.com");
request.Method = "GET";
request.BeginGetResponse((IAsyncResult result) =>
{
HttpWebRequest webRequest = result.AsyncState as HttpWebRequest;
HttpWebResponse webResponse = (HttpWebResponse)webRequest.EndGetResponse(result);
Stream streamResult = webResponse.GetResponseStream();
StreamReader reader = new StreamReader(streamResult);
//获取的返回值
resultString = reader.ReadToEnd();
}, request);
return resultString;
}
第二种方式的代码如下:
public delegate void GetResultEventHandler(object sender, string e);
public event GetResultEventHandler OnGetInfoCompleted;
private void Reqest()
{
HttpWebRequest request = HttpWebRequest.CreateHttp("http://www.google.com");
request.Method = "GET";
request.BeginGetResponse(GetInfoCompleted, request);
}
protected void GetInfoCompleted(IAsyncResult asyncResult)
{
try
{
HttpWebRequest webRequest = asyncResult.AsyncState as HttpWebRequest;
HttpWebResponse webResponse = (HttpWebResponse)webRequest.EndGetResponse(asyncResult);
Stream streamResult = webResponse.GetResponseStream();
StreamReader reader = new StreamReader(streamResult);
//获取的返回值
string resultString = reader.ReadToEnd();
if (OnGetInfoCompleted != null)
{
OnGetInfoCompleted(this, resultString);
}
}
catch (WebException ex)
{
MessageBox.Show(ex.Message);
}
}
第三种方式的代码实现如下:
private async resultString Reqest()
{
HttpWebRequest request = HttpWebRequest.CreateHttp("http://www.google.com");
request.Method = "GET";
HttpWebResponse webResponse = await request.GetResponseAsync();
Stream streamResult = response.GetResponseStream();
StreamReader reader = new StreamReader(streamResult, new GB2312.GB2312Encoding());
string resultString = reader.ReadToEnd();
return resultString;
}
因为有时候请求会有嵌套关系,比如在请求第二个数据之前,需要先请求第一个数据,所以用第一种方式会一直匿名很多层,让我觉得很不爽。
在没有async CTP for windows phone之前,我一直用第二种方式来写代码,因为这样逻辑比较清楚。只是事件的模型看起来也不完美,但这也算是比较常用的异步模型,用事件来传递参数。缺点是当逻辑需要阻塞线程的时候,却又阻塞不了。
我想这也是async框架出现的原因吧。
在windows8的开发中,async框架已成为正式版,也就是说已经完全支持了第三种异步模型,也就是以async,await为主导的模型。这样即可以让需要等待的代码阻塞着,又可以让UI线程保持通畅,并且代码的逻辑也能很清楚,又避开了线程同步的数据锁的麻烦。
算是在这件事情上现阶段较为完美的方案了。
抛砖引玉,大家积极讨论。
顺便庆祝升星,炎热的夏天,散点分。 --------------------编程问答-------------------- nice!
........... --------------------编程问答-------------------- 学习了 --------------------编程问答-------------------- 我都是用第二种方式 第三种方式第一次见 学习了 --------------------编程问答-------------------- 谢版主分享。
最近超热心。 --------------------编程问答-------------------- --------------------编程问答-------------------- 挺好的 不错
--------------------编程问答-------------------- 挺好的 不错
--------------------编程问答-------------------- 学习了 感谢分享~ --------------------编程问答-------------------- 多谢分享 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 大家积极讨论。 --------------------编程问答-------------------- 大家积极讨论。 --------------------编程问答-------------------- 学习了,虽然还看不懂 --------------------编程问答-------------------- 学习了,感谢楼主分享! --------------------编程问答-------------------- 好好看看 --------------------编程问答-------------------- 谢谢分享,收藏了 --------------------编程问答--------------------
谢谢分享! --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 你回答的很不错呀 --------------------编程问答-------------------- 好贴 学习了 --------------------编程问答-------------------- --------------------编程问答-------------------- 学习了
--------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 楼主,第3种是属于同步吧. --------------------编程问答-------------------- --------------------编程问答-------------------- Ultimate Toolbox --------------------编程问答-------------------- 好东西! --------------------编程问答-------------------- --------------------编程问答-------------------- 没又wp --------------------编程问答-------------------- 不对吧 你的程序 --------------------编程问答-------------------- 谢谢楼主哈!!!!!! --------------------编程问答-------------------- 谢谢楼主哈!!!!!!! --------------------编程问答-------------------- 谢谢 楼主 哈啊 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 谢谢分享··· --------------------编程问答-------------------- 感谢楼主分享! --------------------编程问答-------------------- 学习了,多谢楼主 --------------------编程问答-------------------- 学习了,多谢楼主 --------------------编程问答-------------------- --------------------编程问答-------------------- 学习了,多谢楼主 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 支持了,谢谢楼主的分享 --------------------编程问答-------------------- 楼主不知道能否提供的同步版的,就要同步的,不要异步的。
http://topic.csdn.net/u/20120713/17/2cfca3fe-a527-4c6c-a397-288629bccbce.html?seed=1733111358&r=79148395#r_79148395
我这个帖子你回复了下,但是,我还是要同步的,你这三个方法都是异步的。 --------------------编程问答-------------------- 顶,好贴 --------------------编程问答--------------------
我不知道你的具体流程和需求,我认为多数情况下,第三种方法应该能满足想达到同步的要求。
你能描述一下你的流程和需求吗? --------------------编程问答--------------------
第三种我试了下,request.GetResponseAsync(); 这个东西,貌似在wp7下没法用,没有这个方法GetResponseAsync
我要同步的方法。我的需求是,比如说:我先抓百度的数据,百度没有再抓谷歌的。
这时候我就要判断,
string html = Helper.LoadHtml("http://www.baidu.com");--------------------编程问答--------------------
if(string.IsNullOrEmpty(html))
{
html = Helper.LoadHtml("http://www.google.com");
}
你需要下载这个sdk (sync ctp v3)
http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=9983
才可以使用async/await,也才相应地有那些后缀为async的方法
如果用第三种方法,你可以用await的方式抓取百度的数据,而后再抓取google的数据。
像这样:
string html = await Helper.LoadHtml("http://www.baidu.com");
if(string.IsNullOrEmpty(html))
{
html = await Helper.LoadHtml("http://www.google.com");
}
但是你需要将你的helper类的LoadHtml方法加以async签名。 --------------------编程问答-------------------- 好贴,先顶 --------------------编程问答-------------------- --------------------编程问答--------------------
非常感谢,确实是如你所说的,可以实现。我去把我的贴结掉,给分。
另外,安装了你说的这个sdk后,还要引用个dll,%MyDocument%\Microsoft Visual Studio Async CTP\Samples\AsyncCtpLibrary_Phone.dll
否则没有GetResponseAsync这个方法。
下面是我对你第三个方法的一点小完善,也是我自己代码中用的方法
public static async Task<string> ReqestAsync(string url)
{
HttpWebRequest request = HttpWebRequest.CreateHttp(url);
request.Method = "GET";
HttpWebResponse webResponse = (HttpWebResponse)await request.GetResponseAsync();
string resultString = string.Empty;
using (Stream streamResult = webResponse.GetResponseStream())
{
using (StreamReader reader = new StreamReader(streamResult))
{
resultString = await reader.ReadToEndAsync();
}
}
webResponse.Close();
return resultString;
}
最后,调用这个方法的方法也要用加 async ,否则会出错,例子:
public async Task<bool> Update()
{
string link="http://www.baidu.com";
string html = await Helper.ReqestAsync(link);
return true;
}
--------------------编程问答-------------------- --------------------编程问答-------------------- 不错不错,mark --------------------编程问答-------------------- 好贴,先顶 --------------------编程问答-------------------- 好贴,顶个 --------------------编程问答-------------------- 大爱楼主 --------------------编程问答-------------------- 还有一种利用 RX 的,当然还是基于 Task 的 异步编程模型最直观,简洁。 --------------------编程问答-------------------- 谢谢LZ分享,LZ好人呐 --------------------编程问答-------------------- --------------------编程问答-------------------- 不错的东西 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 不错 不错 学习了 --------------------编程问答-------------------- 这么好的帖子 学习了· --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 很有用,收藏了! --------------------编程问答-------------------- 更上一层楼啊 --------------------编程问答-------------------- 第三种await就是传说中windows 8的全新线程方式吧 --------------------编程问答-------------------- 标记、学习以及收藏。 感谢楼主分享。 --------------------编程问答-------------------- 如果需要下载的数据量很大的话,会不会出现多次回调的情况,那么像第二种方法会不会有问题????希望楼主解答. --------------------编程问答-------------------- 学习~楼主好人 --------------------编程问答--------------------
几次回调只和几次请求有关。
数据量很大只会出现回调的响应时间很长的问题。 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 学习一下 --------------------编程问答-------------------- 每天回帖即可获得10分可用分!小技巧:教您如何更快获得可用分 --------------------编程问答-------------------- 受教,呵呵,收藏~~ --------------------编程问答-------------------- 楼主,你好,看了您的帖子很受启发的说,但是就第三种方式,我在我的环境下无法实现,HttpWebResponse webResponse = await request.GetResponseAsync();,其中request中没有GetResponseAsync这个方法,我是VS2012,wp8环境,不知道你们是怎么实现的,让UI线程等待HttpWebRequest取得数据,希望能够得到您的指点,万分感谢。 --------------------编程问答--------------------
你得安装async ctp --------------------编程问答-------------------- 第三种方式很好,不过楼主的代码是不是有问题
private async resultString Reqest()
async 后面必须要跟Task<T> 参数,结合你的上下文,这样写肯定通不过编译 --------------------编程问答-------------------- 正确的写法应该是
private async Task<string> Reqest()
--------------------编程问答--------------------
你可以编译试一下:) --------------------编程问答-------------------- 为啥返回值为null呢? --------------------编程问答--------------------
哪里返回null --------------------编程问答--------------------
public delegate void GetResultEventHandler(object sender, string e);
public event GetResultEventHandler OnGetInfoCompleted;
private void Reqest(string str)
{
System.Net.HttpWebRequest request = System.Net.HttpWebRequest.CreateHttp(str);
request.Method = "GET";
request.BeginGetResponse(GetInfoCompleted, request);
}
protected void GetInfoCompleted(IAsyncResult asyncResult)
{
try
{
System.Net.HttpWebRequest webRequest = asyncResult.AsyncState as System.Net.HttpWebRequest;
System.Net.HttpWebResponse webResponse = (System.Net.HttpWebResponse)webRequest.EndGetResponse(asyncResult);
System.IO.Stream streamResult = webResponse.GetResponseStream();
System.IO.StreamReader reader = new System.IO.StreamReader(streamResult);
//获取的返回值
string resultString = reader.ReadToEnd();
System.Windows.MessageBox.Show(resultString);
if (OnGetInfoCompleted != null)
{
OnGetInfoCompleted(this, resultString);
}
}
catch (System.Net.WebException ex)
{
System.Windows.MessageBox.Show(ex.Message);
}
}
输出提示错误 --------------------编程问答--------------------
楼主,为啥这个一输出就提示错误呢?
补充:移动开发 , Windows Phone