2013 年编辑: async
现在await
让这变得微不足道!:-)
我有一些屏幕抓取网站的代码(仅用于说明目的!)
public System.Drawing.Image GetDilbert()
{
var dilbertUrl = new Uri(@"http://dilbert.com");
var request = WebRequest.CreateDefault(dilbertUrl);
string html;
using (var webResponse = request.GetResponse())
using (var receiveStream = webResponse.GetResponseStream())
using (var readStream = new StreamReader(receiveStream, Encoding.UTF8))
html = readStream.ReadToEnd();
var regex = new Regex(@"dyn/str_strip/[0-9/]+/[0-9]*\.strip\.gif");
var match = regex.Match(html);
if (!match.Success) return null;
string s = match.Value;
var groups = match.Groups;
if (groups.Count > 0)
s = groups[groups.Count - 1].ToString(); // the last group is the one we care about
var imageUrl = new Uri(dilbertUrl, s);
var imageRequest = WebRequest.CreateDefault(imageUrl);
using (var imageResponse = imageRequest.GetResponse())
using (var imageStream = imageResponse.GetResponseStream())
{
System.Drawing.Image image_ = System.Drawing.Image.FromStream(imageStream, true /*useEmbeddedColorManagement*/, true /*validateImageData*/);
return (System.Drawing.Image)image_.Clone(); // "You must keep the stream open for the lifetime of the Image."
}
}
现在,我想异步调用 GetDilbert()。使用委托的简单方法:
Func<System.Drawing.Image> getDilbert;
IAsyncResult BeginGetDilbert(AsyncCallback callback, object state)
{
getDilbert = GetDilbert;
return getDilbert.BeginInvoke(callback, state);
}
System.Drawing.Image EndGetDilbert(IAsyncResult result)
{
return getDilbert.EndInvoke(result);
}
虽然这确实有效,但它的效率并不高,因为委托线程将花费大部分时间等待两个 I/O 操作。
我想做的是打电话request.BeginGetResponse()
,做正则表达式匹配,然后打电话imageRequest.BeginGetResponse()
。同时使用标准异步调用模式并保留BeginGetDilbert()和EndGetDilbert()的签名。
我尝试了几种方法,但对其中任何一种都不完全满意;这似乎是一种皇家的痛苦。因此,问题。:-)
编辑: C# 编译器团队似乎不赞成使用迭代器的方法。
编译器团队的请求:
虽然可以肯定的是,您可以使用迭代器来实现状态机、穷人协程等等,但我希望人们不要这样做。
请按照预期目的使用工具。如果您想编写状态机,请为自己编写一个专门用于解决该一般问题的库,然后使用它。
将工具用于预期目的之外的目的是“聪明的”,聪明是坏的;聪明让维护程序员难以理解,聪明难以扩展,聪明难以推理,聪明让人“开箱即用”;那个盒子里有好东西。
选择Future<>
答案,因为它保留在 C# 中,这与我的示例代码相同。不幸的是,TPL 和 F# 都没有得到 Microsoft 的官方支持……但是。