Search code examples
c#.netasync-await

async await execution order - code only actually works when stepping through/debugging


I'm hoping there is a simple answer here, and this is probably due to my misunderstanding of asynchronous operations...

I have a method that can be started manually or can autostart when the program loads. The async method works perfectly when invoked manually (on button press). However, when autoloaded the method just seems to skip the main "await" part of the method without performing any work, and skips straight to the end.

The whole process starts in this method:

private void StartBatch()
{
    var batchSize = (int)BatchSizeSlider.Value;

    if (_config.AutoStart)
    {
        ExecutionLogAddItem(string.Format("Auto batch processing started (batch size: {0})", batchSize.ToString()));

        Task.Factory.StartNew(async () =>
        {
            await BatchTransfer(batchSize);
            CompleteBatch();
        });
    }
    else
    {
        var start = ConfirmStartBatch();
        var doBatch = start.ContinueWith(async (continuation) =>
        {
            //start task
            if (start.Result == true)
            {
                ExecutionLogAddItem("Batch processing started.");
                ExecutionLogAddItem(string.Format("Batch size set at {0}", batchSize.ToString()));
                await BatchTransfer(batchSize).ContinueWith((x) => CompleteBatch());
            }
            else
            {
                ExecutionLogAddItem("Batch processing aborted.");
            }
        });    
    }
}

If _config.AutoStart is true, the BatchTransfer method doesn't seem to do anything, instead the program skips straight to the CompleteBatch() method. If invoked manually everything works as expected.

The strange thing is, if I set a breakpoint on await BatchTransfer(batchSize) in the autostarted method, I can step through the code and the batch transfers take place. So when debugging it works, when not debugging it doesn't. Please help!


Solution

  • It is because -

    Task.Factory.StartNew(async () =>
        {
            await BatchTransfer(batchSize);
            CompleteBatch();
        });
    

    You are waiting for the inner task to complete with await but Task.Factory.StartNew(async () => itself is an asynchronous task and is not awaited. You should also wait for Task.Factory.StartNew(async () => like this -

    await Task.Factory.StartNew(async () =>
    

    When you are debugging, the separate thread that is calling inner task is held and you can see the execution but when running normally the background is still working, but you cannot see it since you didn't wait for the Task.Factory.StartNew(async () =>.

    If you check the thread pool and thread id, I am sure you will see that they are different when debugging.

    This blog might help you understand the situation - Task.Run vs Task.Factory.StartNew.