vendredi 31 juillet 2015

Correct way to link Tasks together when return values are needed at different times #2

I asked a question yesterday and, unfortunately, even with the answers provided, I'm still hitting up on stumbling blocks about how to do things correctly... My issue is that my code actually works, but I'm a complete novice at concurrency programming and it feels like I'm not programming the correct way and, most importantly, I'm afraid of developing bad habits.

To make up a simplistic example to elaborate on yesterday's question, suppose I had the following methods:

static Task<IEnumerable<MyClass>> Task1(CancellationToken ct)

static Task<IEnumerable<int>> Task2(CancellationToken ct, List<string> StringList)

static Task<IEnumerable<String>> Task3(CancellationToken ct)

static Task<IEnumerable<Double>> Task4(CancellationToken ct)

static Task Task5(CancellationToken ct, IEnumerable<int> Task2Info, IEnumerable<string> Task3Info, IEnumerable<double> Task4Info)

static Task Task6(CancellationToken ct, IEnumerable<int> Task2Info, IEnumerable<MyClass> Task1Info)

And the code I've written that utilizes them looks as follows:

static Task execute(CancellationToken ct)
{
    IEnumerable<MyClass> Task1Info = null;
    List<string> StringList = null;
    IEnumerable<int> Task2Info = null;
    IEnumerable<string> Task3Info = null;
    IEnumerable<double> Task4Info = null;

    var TaskN = Task.Run(() =>
                    {
                        Task1Info = Task1(ct).Result;
                    }
                    , ct)
                    .ContinueWith(res =>
                    {
                        StringList = Task1Info.Select(k=> k.StringVal).ToList();
                        Task2Info = Task2(ct, StringList).Result;
                    }
                    , ct);

    return Task.Run(() =>
    {
        return Task.WhenAll
            (
                TaskN,
                Task.Run(() => { Task3Info = Task3(ct).Result; }, ct),
                Task.Run(() => { Task4Info = Task4(ct).Result; }, ct)
            )
            .ContinueWith(res =>
            {
                Task5(ct, Task2Info, Task3Info, Task4Info).Wait();
            }
            , ct)
            .ContinueWith(res =>
            {
                Task6(ct, Task2Info, Task1Info).Wait();
            }
            , ct);
    });
}

In other words:

  • I need the results of Task1 to calculate StringList and to run Task2
  • Task2, Task3 and Task4 can all run concurrently
  • I need the return values from all of the above for later method calls
  • Once these are run, I use their results to run Task5
  • Once Task5 is run, I use all the results in running Task6

As a simple explanation, imagine the first portion is data gathering, the second is data cleansing and the third data reporting

Like I said, my challenge is that this actually runs, but I simply feel that it's more of a "hack" that the right way to program - Concurrency programming is very new to me and I definitely want to learn the best ways this should be done...

Aucun commentaire:

Enregistrer un commentaire