使用TPL的WebClient请求的树层次结构

时间:2011-09-12 08:15:44

标签: c# asynchronous task task-parallel-library

我正在用C#开发一个WPF应用程序,我有一个Uri,我想下载Json数据。该代码将下载的Json数据反序列化为对象,此后,该对象具有Uris列表,该列表需要请求更多我希望并行请求的Json数据。并且下载的Json数据可能有更多要求的Uris。在需要时,代码应该能够在父级及其子级WebClient上执行WebClient.CancelAsync。我正在查看任务并行库,发现很难掌握和实现它。我不确定是否应该使用TPL的Cancellation令牌来调用CancelAsync或CancelAsync来取消TPL的Cancellation令牌。而且我不确定我是否应该为子WebClient使用嵌套的任务....?

如果有人有类似的情况并使用新的TPL实现它。你会介意共享一段代码...

感谢。

2 个答案:

答案 0 :(得分:1)

如果我可以建议在TPL之上使用Reactive Extensions (Rx),那么这可以非常轻松地完成,而无需取消任务等。

如果我可以假设你有以下内容:

// The initial Uri
Uri initialUri = ...;

// A function to return the JSON string from a given Uri
Func<Uri, string> getJason = ...; 

// Turn the JSON into the next set of Uris to fetch
Func<string, IEnumerable<Uri>> getUris = ...; 

然后,使用Rx,将这些函数转换为使用任务池返回可观察对象的函数,如下所示:

Func<Uri, IObservable<string>> getJasonObsFunc = u =>
    Observable
        .FromAsyncPattern<Uri, string>(
            getJason.BeginInvoke,
            getJason.EndInvoke)
        .Invoke(u)
        .ObserveOn(Scheduler.TaskPool);

Func<string, IObservable<Uri>> getUrisObsFunc = j =>
    Observable
        .FromAsyncPattern<string, IEnumerable<Uri>>(
            getUris.BeginInvoke,
            getUris.EndInvoke)
        .Invoke(j)
        .ObserveOn(Scheduler.TaskPool)
        .SelectMany(xs => xs.ToObservable());

您需要回调才能获得Uri / JSON对。像这样:

Action<Uri, string> callback = (u, j) =>
    Console.WriteLine(String.Format("{0} => {1}", u, j));

这是递归LINQ查询,它将以递归方式获取每个JSON字符串:

Func<Uri, IObservable<Uri>> getAllUris = null;
getAllUris = u =>
    Observable
        .Return<Uri>(u)
        .Merge(
            from j in getJasonObsFunc(u).Do(k => callback(u, k))
            from u1 in getUrisObsFunc(j)
            from u2 in getAllUris(u1)
            select u2);

然后使用以下行调用所有这些优点:

var subscription = getAllUris(initialUri).Subscribe();

现在,如果要取消查询执行,请调用:

subscription.Dispose();

Rx处理所有任务并为您取消所有任务。

我希望这会有所帮助。

以下是Rx的链接:

答案 1 :(得分:0)

我建议你避免创建嵌套任务,因为你无法控制正在运行的任务的数量,而是可以使用BlockingCollection使用调度模式,其中工作任务数量有限,他们从集合中调度工作,如有必要,他们可以为其添加更多工作,当下载所有对象时,您可以调用CompleteAdding来取消阻止所有等待任务。