使用TPL的WebClient请求的树状结构

本文关键字:结构 WebClient TPL 使用 请求 | 更新日期: 2023-09-27 18:08:12

我正在c#中开发一个WPF应用程序,我有一个Uri,我想下载Json数据。代码将下载的Json数据反序列化到对象,此后,对象有一个uri列表,需要请求更多的Json数据,我想并行请求。并且下载的Json数据可能有更多uri要请求。代码应该能够做WebClient。如果需要的话,在父类和子类的WebClient上取消async。我正在看任务并行库,发现很难掌握和实现它。我不确定是否应该使用TPL的取消令牌来调用CancelAsync或CancelAsync来取消TPL的取消令牌。我不确定我是否应该使用嵌套任务的孩子WebClient....?

如果有人有类似的场景,并使用新的TPL实现它…你介意分享一段代码吗…

谢谢。

使用TPL的WebClient请求的树状结构

如果我可以建议在TPL之上使用响应式扩展(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的链接:

    响应式扩展论坛
  • 响应扩展(Rx) v1.0.10621

我建议您避免创建嵌套任务,因为您失去了对运行任务数量的控制,相反,您可以使用调度模式使用BlockingCollection,其中有有限数量的工作任务,它们从集合中调度工作,如果有必要,它们可以添加更多的工作,当所有对象都下载后,您调用CompleteAdding来取消阻塞所有等待任务。