我的目标是同时加载多个链接并为每个链接创建一个任务。
该任务将调用异步方法,该方法将解析链接并返回子链接,这些链接将被解析(使用WebBrowser),然后返回下载链接。
第一个异步方法将调用2个后续方法来完成该工作。
我的问题是Task.Factory.ContinueWhenAll只会在所有第一个方法完成时返回,并且不会等待其余的工作完成。我只想继续准备所有下载链接,这可能需要多个网页解析才能实现。
目前我的代码如下:
var tasks = new List<Task>();
for (var index = 0; index < items_checklist.CheckedItems.Count; index++)
{
var item = items_checklist.CheckedItems[index];
Task task = Task.Factory.StartNew(
() => GetMirrors(((Item) item).Value, ((Item) item).Text)
, CancellationToken.None
, TaskCreationOptions.None
, TaskScheduler.FromCurrentSynchronizationContext()
);
tasks.Add(task);
}
Task.Factory.ContinueWhenAll(tasks.ToArray(), GetLinks_Finished =>
{
SetLinksButtonText(@"Links Ready");
SetLinksButtonState(false);
SetDownloadButtonState(true);
Cursor.Current = DefaultCursor;
});
当所有GetMirrors完成但GetMirrors将调用&#34; tempbrowser_DocumentCompleted&#34; (WebBrowser完成事件)反过来调用&#34; LoadLinkIntoQueue&#34;将下载链接加载到队列中。
我希望在执行所有LoadLinkIntoQueue时继续ContinueWhenAll。
我缺少什么逻辑?
答案 0 :(得分:2)
您可以在GetMirrors
方法中创建TaskCompletionSource,这是您要处理的for循环中Task.Factory.StartNew
调用中使用的方法。
在GetMirrors
中,您将连接新WebBrowser的DocumentCompleted事件,该事件将调用TaskCompletionSource上的SetResult
,使任务转换为已完成。
您的实施将是这样的:
Task<string> GetMirrors(string url, string somethingelse )
{
// this will signal that the Task is completed
// we want the parent to wait
var tcs = new TaskCompletionSource<string>(TaskCreationOptions.AttachedToParent);
// give each task their own WebBrowser instance
WebBrowser tempbrowser = new WebBrowser();
tempbrowser.ScriptErrorsSuppressed = true;
this.Controls.Add(tempbrowser);
tempbrowser.DocumentCompleted += (s, e) => {
// LoadLinkIntoQueue call
// we have a result so signal to the CompletionSource that we're done
tcs.SetResult(e.Url.ToString());
this.Controls.Remove(tempbrowser);
};
// hook up errorhandling if you need that, left as an exercise.
tempbrowser.Navigate(url);
// we return the Task from the completion source
return tcs.Task ;
}
如果要返回发生的异常,也可以在TaskCompletionSource实例上调用SetException。
请注意,在此代码中,我为每个任务实例化WebBrowser,因此您不必担心将任务序列化为只有一个WebBrowser控件处理任务。