0

I have a method that creates a task, and executes a Action as a new task, and after a period of time if it's not finished, it kills it. Here is the code:

static bool ExecuteWithTimeLimit(TimeSpan timeSpan, Action codeBlock)
{
    try
    {
        Task task = Task.Factory.StartNew(() => codeBlock());
        if (!task.Wait(timeSpan))
        {
            Console.WriteLine("Time exceeded. Aborted!");
        }
        return task.IsCompleted;
    }
    catch (AggregateException ae)
    {
        throw ae.InnerExceptions[0];
    }
}        

This method I call from another place.

public static async Task<List<LMAXData>> GetExposure()
{
    var accountsPositions = new List<LMAXData>();

    foreach (var account in accounts)
    {
        LMAXInterfаce lmax = new LMAXInterfаce(account.user, account.password);
        ExecuteWithTimeLimit(TimeSpan.FromMilliseconds(5000), lmax.StartInterface);

        accountsPositions.AddRange(lmax.GetLMAXData().GroupBy(x => x.instrument).Select(i => i.First()).ToList());
    }

    return accountsPositions;
}

My final goal is to create a parallel task for every account, that will start the lmax.StartInterface method, which will collect data and add it to my accountsPositions local List.

But the problem is that it's too slow if you have 10 accounts because it takes 5 seconds for each account to collect the data.

I want to run those 10 account Tasks in parallel, wait for 5 seconds, and then kill all and take the results. Is there a way to do that ?

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
pewocis495
  • 117
  • 1
  • 11

1 Answers1

1

First, you are doing something weird in ExecuteWithTimeLimit, as you are never "Aborting" nor "Killing" the task. Task will complete eventually but you are "forgetting" about it. You are also not returning a Task Result.

Regarding your question, yes it's possible and easy, just start tasks and do WaitAny(tasks, timeSpan) https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.waitany?view=net-6.0 , then check what has completedapart from task returned from WaitAny, and take Result.

However I would rethink the design again, as the construction seems to be weird. GetExposure is an async Task already and you can simply use it.

// this will create 10 tasks
var tasks = Enumerable.Range(1,10).Select(_=>GetExposure()).ToArray();

//this will wait for any finished or proceed
var tn = Task.WaitAny(tasks, timeSpan);

if(tn!=-1){
 DoSomthing(tasks[tn].Result);
}
// check other if needed 
foreach(t in tasks){
 if(t.IsCompleted){
  DoSomthing(t.Result);
 }
}

for cancelling task properly you should implement CancelationToken

MikolajR
  • 81
  • 4