Древовидная иерархия запросов WebClient с использованием TPL - PullRequest
0 голосов
/ 12 сентября 2011

Я разрабатываю приложение WPF на C #, где у меня есть Uri, для которого я хочу загрузить данные Json.Код будет десериализовать загруженные данные Json в объект, после этого у объекта будет список Uris, для которого потребуется запросить больше данных Json, которые я бы хотел запросить параллельно.И загруженные данные Json могут запросить больше Uris.Код должен быть в состоянии сделать WebClient.CancelAsync на родительском и дочернем WebClient при желании.Я смотрю на библиотеку параллельных заданий, и мне трудно ее понять и реализовать.Я не уверен, стоит ли использовать токен отмены TPL для вызова CancelAsync или CancelAsync для отмены токена отмены TPL.И я не уверен, стоит ли мне использовать вложенные Задачи для детей. WebClient ....?

Если у кого-то есть подобный сценарий и он реализован с использованием нового TPL .., не могли бы вы поделиться фрагментом кода...

Спасибо.

Ответы [ 2 ]

1 голос
/ 14 сентября 2011

Если я могу предложить использовать Reactive Extensions (Rx) поверх TPL, то это можно сделать довольно легко без необходимости отмены задач и т. Д.

Если я могу предположить, что у вас есть следующее:

// 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:

0 голосов
/ 14 сентября 2011

Я бы порекомендовал вам избегать создания вложенных задач, потому что вы теряете контроль над количеством запущенных задач, вместо этого вы можете использовать шаблон диспетчеризации с помощью BlockingCollection, где существует ограниченное количество рабочих задач, они распределяют работу из коллекции иони могут добавить к нему больше работы, если необходимо, и когда все объекты загружены, вы вызываете CompleteAdding, чтобы разблокировать все ожидающие задачи.

...