Есть ли правильный шаблон для нескольких методов ContinueWith - PullRequest
0 голосов
/ 03 декабря 2018

В документах для TPL я нашел эту строку:

Вызов нескольких продолжений из одного и того же прошлого

Но это не объясняетсядальшеЯ наивно полагал, что вы могли бы связать ContinueWiths аналогичным образом, пока вы не нажмете правую TaskContinuationOptions.

TaskThatReturnsString()
    .ContinueWith((s) => Console.Out.WriteLine(s.Result), TaskContinuationOptions.OnlyOnRanToCompletion)
    .ContinueWith((f) => Console.Out.WriteLine(f.Exception.Message), TaskContinuationOptions.OnlyOnFaulted)
    .ContinueWith((f) => Console.Out.WriteLine("Cancelled"), TaskContinuationOptions.OnlyOnCanceled)
    .Wait();

Но это не сработает, как я надеялся, по крайней мере, двапричины.

  • Продолжения правильно связаны, поэтому 2nd ContinueWith получает результат от 1st, который реализуется как новая задача, в основном сама задача ContinueWith.Я понимаю, что строка может быть возвращена вперед, но не будет ли это новой задачей с потерей другой информации?
  • Поскольку первая опция не выполнена, задача просто отменяется.Это означает, что второй набор никогда не будет выполнен, а исключения потеряны.

Так что они имеют в виду в документах, когда говорят несколько продолжений от одного и того же происхождения?Для этого есть подходящий паттерн, или нам просто нужно обернуть вызовы в блоки try catch?


РЕДАКТИРОВАТЬ

Так что я думаю, это было то, что яя надеялся, что смогу это сделать, обратите внимание, что это упрощенный пример.

    public void ProccessAllTheThings()
    {
        var theThings = util.GetAllTheThings();
        var tasks = new List<Task>();
        foreach (var thing in theThings)
        {
            var task = util.Process(thing)
                        .ContinueWith((t) => Console.Out.WriteLine($"Finished processing {thing.ThingId} with result {t.Result}"), TaskContinuationOptions.OnlyOnRanToCompletion)
                        .ContinueWith((t) => Console.Out.WriteLine($"Error on processing {thing.ThingId} with error {t.Exception.Message}"), TaskContinuationOptions.OnlyOnFaulted);
            tasks.Add(task);
        }
        Task.WaitAll(tasks.ToArray());
    }

Поскольку это было невозможно, я подумал, что мне придется заключать каждый вызов задачи в цикл try внутри цикла, чтобы я не могОстановить процесс, но не ждать его там.Я не был уверен, какой правильный путь.

Иногда решение просто смотрит вам в лицо, это сработает, не так ли?

    public void ProccessAllTheThings()
    {
        var theThings = util.GetAllTheThings();
        var tasks = new List<Task>();
        foreach (var thing in theThings)
        {
            var task = util.Process(thing)
                .ContinueWith((t) =>
                {
                    if (t.Status == TaskStatus.RanToCompletion)
                    {
                        Console.Out.WriteLine($"Finished processing {thing.ThingId} with result {t.Result}");
                    }
                    else
                    {
                        Console.Out.WriteLine($"Error on processing {thing.ThingId} - {t.Exception.Message}");
                    }
                });
            tasks.Add(task);
        }
        Task.WaitAll(tasks.ToArray());
    }

1 Ответ

0 голосов
/ 03 декабря 2018

Что вы сделали, это создали последовательную цепочку из нескольких задач.

Что вам нужно сделать, это присоединить все ваши задачи продолжения к первой:

var firstTask = TaskThatReturnsString();
var t1 = firstTask.ContinueWith (…);
var t2 = firstTask.ContinueWith (…);
var t3 = firstTask.ContinueWith (…);

Тогда вам нужнождать всех продолжений задачи:

Task.WaitAll (t1, t2, t3);
...