C# 运行 解析网站的多个任务和 return 当它们全部完成时
C# Run multiple tasks that parse website and return when they all finish
我的objective是同时加载多个link并为每个
创建一个任务
该任务将调用一个异步方法来解析 links 和 returns 子 links,在 return 中将被解析(使用 WebBrowser ) 然后他们 return 下载 link.
第一个异步方法将调用 2 个后续方法来完成该工作。
我的问题是 Task.Factory.ContinueWhenAll 仅当所有第一个方法完成时才会 return,并且不会等待其余工作完成。我只想在所有下载 link 准备就绪后继续,这可能需要多个网页解析才能完成。
目前我的代码如下:
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;
});
这将 return 当所有 GetMirrors 完成时,但 GetMirrors 会调用 "tempbrowser_DocumentCompleted"(WebBrowser 完成事件),后者又会调用 "LoadLinkIntoQueue" 将下载 link 加载到排队。
我希望 ContinueWhenAll 在执行完所有 LoadLinkIntoQueue 后恢复。
我缺少什么逻辑?
您可以在 GetMirrors
方法中创建一个 TaskCompletionSource,这是在要处理的 url 循环中 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 ;
}
如果您想 return 发生异常,也可以在 TaskCompletionSource 实例上调用 SetException。
请注意,在这段代码中,我为每个任务实例化了一个 WebBrowser,因此您不必担心将任务序列化为仅让一个 WebBrowser 控件处理一个任务。
我的objective是同时加载多个link并为每个
创建一个任务该任务将调用一个异步方法来解析 links 和 returns 子 links,在 return 中将被解析(使用 WebBrowser ) 然后他们 return 下载 link.
第一个异步方法将调用 2 个后续方法来完成该工作。
我的问题是 Task.Factory.ContinueWhenAll 仅当所有第一个方法完成时才会 return,并且不会等待其余工作完成。我只想在所有下载 link 准备就绪后继续,这可能需要多个网页解析才能完成。
目前我的代码如下:
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;
});
这将 return 当所有 GetMirrors 完成时,但 GetMirrors 会调用 "tempbrowser_DocumentCompleted"(WebBrowser 完成事件),后者又会调用 "LoadLinkIntoQueue" 将下载 link 加载到排队。
我希望 ContinueWhenAll 在执行完所有 LoadLinkIntoQueue 后恢复。
我缺少什么逻辑?
您可以在 GetMirrors
方法中创建一个 TaskCompletionSource,这是在要处理的 url 循环中 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 ;
}
如果您想 return 发生异常,也可以在 TaskCompletionSource 实例上调用 SetException。
请注意,在这段代码中,我为每个任务实例化了一个 WebBrowser,因此您不必担心将任务序列化为仅让一个 WebBrowser 控件处理一个任务。