C#运行解析网站的多个任务,并在完成后返回

时间:2017-12-28 16:13:22

标签: c# async-await task multitasking

我的目标是同时加载多个链接并为每个链接创建一个任务。

该任务将调用异步方法,该方法将解析链接并返回子链接,这些链接将被解析(使用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。

我缺少什么逻辑?

1 个答案:

答案 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控件处理任务。