2013年編集: async
そしてawait
今、これを簡単にしましょう!:-)
Web サイトをスクリーン スクレイピングするコードをいくつか用意しました (説明のみを目的としています)。
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);
}
これは確かに機能しますが、デリゲート スレッドが 2 つの I/O 操作の待機にほとんどの時間を費やすため、あまり効率的ではありません。
私がやりたいことは、 を呼び出しrequest.BeginGetResponse()
、正規表現の一致を実行してから、 を呼び出すことimageRequest.BeginGetResponse()
です。すべて標準の非同期呼び出しパターンを使用し、BeginGetDilbert()とEndGetDilbert( ) の署名を保持します。
私はいくつかのアプローチを試しましたが、完全に満足できるものはありませんでした。これは王道の痛みのようです。したがって、質問です。:-)
編集: イテレータを使用するアプローチは、C# コンパイラ チームによって眉をひそめられているようです。
コンパイラ チームからのお願い:
イテレータを使用してステート マシンや貧弱なコルーチンなどを実装できるのは確かですが、そうしないでほしいと思います。
ツールは本来の目的のために使用してください。ステート マシンを作成する場合は、その一般的な問題を解決するために特別に設計されたライブラリを自分で作成し、それを使用します。
意図したもの以外の目的でツールを使用することは「賢い」ことであり、賢いことは悪いことです。巧妙さはメンテナンス プログラマーにとって理解するのが難しく、巧妙さは拡張しにくく、巧妙さについて推論するのは難しく、巧妙さは人々に「箱から出して」考えさせます。その箱の中に良いものが入っています。
Future<>
それは私のサンプルコードと同じC#にとどまるため、答えに行きます。残念ながら、TPL も F# も Microsoft によって正式にサポートされていません...まだです。