PTL の調査を始めたばかりで、設計に関する質問があります。
私のシナリオ: それぞれが画像を参照する URL のリストがあります。各画像を並行してダウンロードしたい。少なくとも 1 つのイメージがダウンロードされるとすぐに、ダウンロードしたイメージで何かを行うメソッドを実行したいと考えています。そのメソッドは並列化すべきではありません。シリアル化する必要があります。
以下はうまくいくと思いますが、これが正しい方法かどうかはわかりません。画像を収集するためのクラスと、収集した画像で「何か」を行うためのクラスが別々にあるため、タスクの配列を渡すことになります。これは、画像の取得方法の内部動作を公開するため、間違っているようです。しかし、私はそれを回避する方法を知りません。実際には、これらの方法の両方にさらに多くの機能がありますが、これは重要ではありません。画像の取得と処理の両方を行う 1 つの大きなメソッドにまとめてはいけません。
//From the Director class
Task<Image>[] downloadTasks = collector.RetrieveImages(listOfURLs);
for (int i = 0; i < listOfURLs.Count; i++)
{
//Wait for any of the remaining downloads to complete
int completedIndex = Task<Image>.WaitAny(downloadTasks);
Image completedImage = downloadTasks[completedIndex].Result;
//Now do something with the image (this "something" must happen serially)
//Uses the "Formatter" class to accomplish this let's say
}
///////////////////////////////////////////////////
//From the Collector class
public Task<Image>[] RetrieveImages(List<string> urls)
{
Task<Image>[] tasks = new Task<Image>[urls.Count];
int index = 0;
foreach (string url in urls)
{
string lambdaVar = url; //Required... Bleh
tasks[index] = Task<Image>.Factory.StartNew(() =>
{
using (WebClient client = new WebClient())
{
//TODO: Replace with live image locations
string fileName = String.Format("{0}.png", i);
client.DownloadFile(lambdaVar, Path.Combine(Application.StartupPath, fileName));
}
return Image.FromFile(Path.Combine(Application.StartupPath, fileName));
},
TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent);
index++;
}
return tasks;
}