简体   繁体   中英

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!

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 - http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx

In order to use await you have to make your method async and call it without Task.Factory.StartNew . One more thing, instead of void make return type as Task of your method because void async are fire and forget. You will not able to track them.

private async Task StartBatch()
{
    await BatchTransfer(batchSize);
    CompleteBatch();
}

Check this link. It have very basic demonstration of async and it is very helpful in understanding how asynchrony works. Six Essential Tips For Async - Introduction . It includes six tips which are very essential. I recommend you go through all of them but to understand current question situation you can go through Tip 1 whose title is Async void is for top-level event-handlers only .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM