简体   繁体   English

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

[英]Tree Hierarchy of WebClient Requests using TPL

I am developing a WPF app in C# where I have an Uri that I want to download Json data. 我正在用C#开发一个WPF应用程序,其中有一个我要下载Json数据的Uri。 The code will deserialize the downloaded Json data to object, thereafter, the object has a list of Uris that would require to request more Json data which i would like to request in parallel. 该代码会将下载的Json数据反序列化为对象,此后,该对象具有Uris列表,该列表将需要请求我想并行请求的更多Json数据。 And the downloaded Json data might have more Uris to request. 并且下载的Json数据可能需要更多Uris请求。 The code should be able to do WebClient.CancelAsync on the parent and its children's WebClient when desired. 如果需要,代码应该能够在父级及其子级的WebClient上执行WebClient.CancelAsync。 I am looking at the Task Parallel Library and finding it difficult to grasp and implement it. 我正在查看任务并行库,发现很难掌握和实现它。 I'm unsure if I should use the TPL's Cancellation token to invoke the CancelAsync or the CancelAsync to cancel the TPL's Cancellation token. 我不确定是否应该使用TPL的Cancellation令牌来调用CancelAsync或CancelCansync来取消TPL的Cancellation令牌。 And I not sure if i should use nested Tasks for the children WebClient....? 而且我不确定是否应该为孩子的WebClient使用嵌套任务。

If anyone has a similar scenario and implemented it using the new TPL.. would you mind sharing a snippet of the code... 如果有人有类似的情况并使用新的TPL来实现。.您介意共享一段代码...

Thanks. 谢谢。

If I can suggest using Reactive Extensions (Rx) on top of the TPL then this can be done quite easily without the need for cancellation tasks etc. 如果我建议在TPL之上使用Reactive Extensions(Rx) ,则可以轻松完成此操作,而无需取消任务等。

If I can assume you have the following: 如果可以假设您具有以下条件:

// 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 = ...; 

Then, using Rx, you turn these functions into functions that return observables using the Task Pool, like so: 然后,使用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());

You'll need a callback to get the Uri/JSON pairs out. 您将需要回调以获取Uri / JSON对。 Something like this: 像这样:

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

Here's the recursive LINQ query that will recursively fetch each JSON string: 这是递归的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);

Then you invoke all of this goodness using the following line: 然后,使用以下行调用所有这些好处:

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

Now, if you want to cancel the query execution just call this: 现在,如果要取消查询执行,只需调用以下命令:

subscription.Dispose();

Rx handles all of the tasks and cancels them all for you. Rx处理所有任务并为您取消所有任务。

I hope this helps. 我希望这有帮助。

Here are the links for Rx: 这是Rx的链接:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM