Alexander_Dracka
Alexander_Dracka

Reputation: 123

Asynchronous Tasks take too much time

I have been trying make an asynchronous approach to my CPU-bound function which compute some aggregate functions. The thing is that there is some Deadlock (I suppose), because the time of calculation is too different. I am reallz newbie in this Task Parallel world, I also read Stephem Cleary articles but I am still unsure of all aspect this asynchronous approach. My Code:

private static void Main(string[] args)
{
    PIServer server = ConnectToDefaultPIServer();
    AFTimeRange timeRange = new AFTimeRange("1/1/2012", "6/30/2012");
    Program p = new Program();
    for (int i = 0; i < 10; i++)
    {
        p.TestAsynchronousCall(server, timeRange);
        //p.TestAsynchronousCall(server, timeRange).Wait();-same results
    }
    Console.WriteLine("Main check-disconnected done");
    Console.ReadKey();
}

private async Task TestAsynchronousCall(PIServer server, AFTimeRange timeRange)
{
    AsyncClass asyn;
    for (int i = 0; i < 1; i++)
    {
        asyn = new AsyncClass();
        await asyn.DoAsyncTask(server, timeRange);
        //asyn.DoAsyncTask(server, timeRange);-same results
    }
}

public async Task DoAsyncTask(PIServer server, AFTimeRange timeRange)
{
        var timeRanges = DivideTheTimeRange(timeRange);
        Task<Dictionary<PIPoint, AFValues>>[] tasksArray = new Task<Dictionary<PIPoint, AFValues>>[2];

        tasksArray[0] = (Task.Run(() => CalculationClass.AverageValueOfTagPerDay(server, timeRanges[0])));
        // tasksArray[1] = tasksArray[0].ContinueWith((x) => CalculationClass.AverageValueOfTagPerDay(server, timeRanges[1]));
        tasksArray[1] = (Task.Run(() => CalculationClass.AverageValueOfTagPerDay(server, timeRanges[1])));


        Task.WaitAll(tasksArray);
        //await Task.WhenAll(tasksArray); -same results
        for (int i = 0; i < tasksArray.Length; i++)
        {
            Program.Show(tasksArray[i].Result);
        }
}

I measure time throught Stopwatch in AverageValueOfTagPerDay functions. This function is synchronous (Is that a problem?). Each Task take 12 seconds. But when I uncommented the line and use ContinueWith() approach, these Tasks take 5-6 seconds each(which is desirable). How is it possible?

More strange is that when I set the for loop in Main() on 10, sometimes it takes 5 seconds as well as when I use ContinueWith(). So I guess somewhere is deadlock but I am unable to find that.

Sorry for english, I got still problem make good senteces when I try explain some difficulties.

Upvotes: 0

Views: 1185

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456507

I have been trying make an asynchronous approach to my CPU-bound function which compute some aggregate functions.

"Asynchronous" and "CPU-bound" are not terms that go together. If you have a CPU-bound process, then you should use parallel technologies (Parallel, Parallel LINQ, TPL Dataflow).

I am reallz newbie in this Task Parallel world, I also read Stephem Cleary articles but I am still unsure of all aspect this asynchronous approach.

Possibly because I do not cover parallel technologies in any of my articles or blog posts. :) I do cover them in my book, but not online. My online work focuses on asynchrony, which is ideal for I/O-based operations.

To solve your problem, you should use a parallel approach:

public Dictionary<PIPoint, AFValues>[] DoTask(PIServer server, AFTimeRange timeRange)
{
  var timeRanges = DivideTheTimeRange(timeRange);
  var result = timeRanges.AsParallel().AsOrdered().
      Select(range => CalculationClass.AverageValueOfTagPerDay(server, range)).
      ToArray();
  return result;
}

Of course, this approach assumes that PIServer is threadsafe. It also assumes that there's no I/O being done by the "server" class; if there is, then TPL Dataflow may be a better choice than Parallel LINQ.

If you are planning to use this code in a UI application and don't want to block the UI thread, then you can call the code asynchronously like this:

var results = await Task.Run(() => DoTask(server, timeRange));
foreach (var result in results)
  Program.Show(result);

Upvotes: 5

Related Questions