Async / Await - 不理解为什么一种方式是阻塞而另一种方式不阻止

时间:2015-06-08 19:25:49

标签: c# async-await

仍然试图绕过async / await。我有以下拖放加载方法:

    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);
        }
    }

正如我所料,它是非阻塞的 - 我可以在TabControl的选项卡之间导航,因为加载了多个项目,我可以看到每个选项卡在完成加载时弹出。

然后我尝试转换为:

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

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

        return Task.FromResult(c);
    }

然后用以下代码替换第一个代码块中标记的代码段:

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

它变得阻塞 - 我无法在加载时浏览标签,然后在完成后立即显示所有加载的项目。只是试着学习和理解这里的差异 - 非常感谢提前。

编辑:

更新了LoadAndCalculateCurve():

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

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

        return c;
    }

3 个答案:

答案 0 :(得分:2)

异步方法不在另一个线程中执行,await不会启动线程。 async仅启用await关键字,await等待已经运行的内容。

所有代码都在UI线程上运行。

答案 1 :(得分:0)

所以基本上这就是我所知道的。

在您编写的第一个代码中

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

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

        AddCurveControls(c);
    }

这会像预期的那样执行异步流,因为您正在使用Task.Run,​​它将工作添加到ThreadPool队列。

在第二次尝试中,您不会这样做而且您正在使用相同的任务。尝试在第二次尝试中使用相同的(Task.Run)逻辑,我认为它将起作用

答案 2 :(得分:0)

LoadAndCalculateCurve方法的实现是同步创建Curve,同步加载并执行计算,然后返回包含在Task中的结果。没有任何关于这是异步的。当你await它将调用该方法时,执行所有同步工作以获得(已完成的)任务,然后为将立即触发的那个(已完成的)任务添加一个继续。

当您改为使用Task.Run时,您会将这些长时间运行的操作安排在另一个线程中,而立即返回一个(尚未完成的)Task您可以用于在最终完成工作时运行代码。