Anthony
Anthony

Reputation: 6502

Async/Await - not understanding why one way is Blocking and another is not

Still trying to wrap my head around async/await. I have the following method for drag/drop loading:

    private async void p_DragDrop(object sender, DragEventArgs e)
    {
        string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);

        List<string> CurvesToLoad = new List<string>();
        List<string> TestsToLoad = new List<string>();

        foreach (string file in files)
        {
            if (file.ToUpper().EndsWith(".CCC"))
                CurvesToLoad.Add(file);
            else if (file.ToUpper().EndsWith(".TTT"))
                TestsToLoad.Add(file);
        }

        //SNIPPET IN BELOW SECTION
        foreach (string CurvePath in CurvesToLoad)
        {
            Curve c = new Curve(CurvePath);

            await Task.Run(() =>
            {
                c.load();
                c.calculate();
            });

            AddCurveControls(c);
        }
        //END SNIPPET

        foreach (string TestPath in TestsToLoad)
        {
            Test t = new Test(TestPath);

            await Task.Run(() =>
            {
                t.load();
            });

            AddTestControls(t);
        }
    }

It is non-blocking as I expected - I am able to navigate between tabs of the TabControl as multiple items are loaded and I can see each tab pop up as it complete loading.

I then tried to convert to this:

    private Task<Curve> LoadAndCalculateCurve(string path)
    {
        Curve c = new Curve(path);

        c.load();
        c.calculate();

        return Task.FromResult(c);
    }

And then replace the marked snippet from the first code block with:

    foreach (string CurvePath in CurvesToLoad)
    {
        Curve c = await LoadAndCalculateCurve(CurvePath);
        AddCurveControls(c);
    }

And it becomes blocking - I can't navigate through tabs as it's loading, and then all of the loaded items appear at once when they are completed. Just trying to learn and understand the differences at play here - many thanks in advance.

EDIT:

Updated LoadAndCalculateCurve():

    private async Task<Curve> LoadAndCalculateCurve(string path)
    {
        Curve c = new Curve(path);

        await Task.Run(() => {
            c.load();
            c.calculate();
        });

        return c;
    }

Upvotes: 1

Views: 114

Answers (3)

Servy
Servy

Reputation: 203838

The implementation of your LoadAndCalculateCurve method is to synchronously create a Curve, synchronously load it and perform the calculation, and then return the result wrapped in a Task. Nothing about this is asynchronously. When you await it it will invoke the method, do all of the synchronous work to get the (already completed) task, and then add a continuation to that (already completed) task that will fire immediately.

When you instead use Task.Run you're scheduling those long running operations to take place in another thread and immediately returning a (not yet completed) Task that you can use to run code when it does eventually finish its work.

Upvotes: 0

usr
usr

Reputation: 171246

Async methods do not execute in a different thread, await does not start a thread. async merely enables the await keyword and await waits for something that already runs.

All of that code is running on the UI thread.

Upvotes: 2

Omar Zaarour
Omar Zaarour

Reputation: 302

So basically this is what is happening to my knowledge.

In your first code you write

    foreach (string CurvePath in CurvesToLoad)
    {
        Curve c = new Curve(CurvePath);

        await Task.Run(() =>
        {
            c.load();
            c.calculate();
        });

        AddCurveControls(c);
    }

this does the async flow as expected because you are using the Task.Run which adds the work to the ThreadPool queue.

In your second try you don't do this and you are using the same task. Try to use the same logic of (Task.Run) in the second try and I think it will work

Upvotes: 0

Related Questions