我正在用C#开发一个WPF应用程序,我有一个Uri,我想下载Json数据。该代码将下载的Json数据反序列化为对象,此后,该对象具有Uris列表,该列表需要请求更多我希望并行请求的Json数据。并且下载的Json数据可能有更多要求的Uris。在需要时,代码应该能够在父级及其子级WebClient上执行WebClient.CancelAsync。我正在查看任务并行库,发现很难掌握和实现它。我不确定是否应该使用TPL的Cancellation令牌来调用CancelAsync或CancelAsync来取消TPL的Cancellation令牌。而且我不确定我是否应该为子WebClient使用嵌套的任务....?
如果有人有类似的情况并使用新的TPL实现它。你会介意共享一段代码...
感谢。
答案 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来取消阻止所有等待任务。