1

In a foreach loop I am using Task.Run, to call a method to do some lengthy operations for each element.

The method I'm calling is an asynch method, but for my purpose, I'm not interested in the return, and I want to return other information to the client.

The problem is that only the quickest call completes and the others are ignored. How could I make sure that each call is called separately on its own thread, without blocking the rest of the code from executing and returning?

foreach (var job in Jobs)
{
    Task.Run(() => _service.DoLongAsyncCall(job)    
}
Curious
  • 57
  • 5
  • I suppose the issue may be caused by the application finishing before all requested tasks are completed. If so, take a look at a similar thread: https://stackoverflow.com/questions/3840795/console-app-terminating-before-async-call-completion – Lukasz M Nov 25 '19 at 21:35
  • 4
    Tasks just don't disappear, your question is missing information – TheGeneral Nov 25 '19 at 21:37
  • 1
    it's hard to know what you want from your description. It's unclear what you mean by "I need to do it synchronously without awaiting the result." because doing something synchronously means you will wait for the result – Keith Nicholas Nov 25 '19 at 22:09
  • The advice in this article is the only one that worked for me, especially approach three. – Curious Nov 27 '19 at 21:00
  • You shouldn't be running long-running background jobs in IIS because the server may decide to recycle for different reasons and your jobs will be unceremoniously kicked to the curb. For this sort of background processing, queue your jobs to a background process (that's not IIS) and do the work there. – xxbbcc Nov 27 '19 at 21:31
  • Thank's xxbbcc, it makes sense what you're saying, although my program has been running for a while the way I suggested bellow, with this call being called a few times each minute, without this causing any problems. – Curious Apr 21 '20 at 18:33

2 Answers2

2

Turn off the current synchronization context state to null, so each call could run independently and not have to run on the current context thus overriding each other.

the following method does exactly that. It runs operations without blocking the main thread when not awaited. And it continues to run even after returning from an API call.

Be careful to use this method only after completing all work that needs to be awaited, as this call interferes with regular async-await patterns.

    public static async Task RunWithoutBlocking(IEnumerable<Func<Task>> actions)
    {
        var currentSyncContext = SynchronizationContext.Current;
        try
        {
            SynchronizationContext.SetSynchronizationContext(null);
            foreach (var action in actions)
            {
                await action();
            }
        }
        finally
        {
            SynchronizationContext.SetSynchronizationContext(currentSyncContext);
        }
    }`

Thanks to "Dan's techie ramblings" for his helpfull article https://www.productiverage.com/i-didnt-understand-why-people-struggled-with-nets-async

Curious
  • 57
  • 5
0

I believe that the quickest one is completing but the others have actually not completed yet. Try something like the following:

List<Task> tasks = new List<Task>();

foreach (var printJob in PrintJobs)
{
    tasks.add(Task.Run(() => _printService.Print(printJob.Label));
}

Task.WaitAll(tasks.ToArray());

This will force the main thread to block until all of the Tasks are completed.

Alex McLean
  • 2,524
  • 5
  • 30
  • 53