【问题标题】:Prevent winforms UI block when using async/await使用 async/await 时防止 winforms UI 阻塞
【发布时间】:2016-02-08 20:12:31
【问题描述】:

我对异步/等待编程还很陌生,有时我觉得我理解它,然后突然发生了一些事情,让我陷入了循环。

我正在测试 winforms 应用程序中对此进行尝试,这是我拥有的一个 sn-p 版本。这样做会阻塞 UI

private async void button1_Click(object sender, EventArgs e)
{

    int d = await DoStuffAsync(c);

    Console.WriteLine(d);

}

private async Task<int> DoStuffAsync(CancellationTokenSource c)
{

        int ret = 0;

        // I wanted to simulator a long running process this way
        // instead of doing Task.Delay

        for (int i = 0; i < 500000000; i++)
        {



            ret += i;
            if (i % 100000 == 0)
                Console.WriteLine(i); 

            if (c.IsCancellationRequested)
            {
                return ret;
            }
        }
        return ret;
}

现在,当我通过将“DoStuffAsync()”的主体包装在 Task.Run 中进行轻微更改时,它工作得非常好

private async Task<int> DoStuffAsync(CancellationTokenSource c)
    {
        var t = await Task.Run<int>(() =>
        {
            int ret = 0;
            for (int i = 0; i < 500000000; i++)
            {



                ret += i;
                if (i % 100000 == 0)
                    Console.WriteLine(i);

                if (c.IsCancellationRequested)
                {
                    return ret;
                }
            }
            return ret;

        });


        return t;
    }

说了这么多,处理这种情况的正确方法是什么?

【问题讨论】:

    标签: c# winforms asynchronous async-await


    【解决方案1】:

    当你编写这样的代码时:

    private async Task<int> DoStuffAsync()
    {
        return 0;
    }
    

    这样你是在同步做事,因为你没有使用await 表达式。

    注意警告:

    此异步方法缺少“等待”运算符,将同步运行。 考虑使用 'await' 运算符来等待非阻塞 API 调用, 或 'await Task.Run(...)' 在后台线程上执行 CPU 密集型工作。

    根据警告建议,您可以通过以下方式进行更正:

    private async Task<int> DoStuffAsync()
    {
        return await Task.Run<int>(() =>
        {
            return 0;
        });
    }
    

    要了解有关 async/await 的更多信息,您可以查看:

    【讨论】:

    • 您输入的第二个选项是我在工作代码中的内容。那么这是处理这个问题的正确和正确的方法吗?
    • 是的。阅读编译器警告。
    • 只是想知道在这种情况下如何编写取消按钮?谢谢。
    • 取消按钮的作用是什么?
    • 如果实现是同步的,您可能希望删除 async 指令并使用return Task.FromResult(...),而不是使用Task.Run
    【解决方案2】:

    您只需要稍微更改 DoStuffAsync 任务,如下所示。

    private async Task<int> DoStuffAsync(CancellationTokenSource c)
    {
         return Task<int>.Run(()=> {
                int ret = 0;
    
                // I wanted to simulator a long running process this way
                // instead of doing Task.Delay
    
                for (int i = 0; i < 500000000; i++)
                {
    
    
    
                    ret += i;
                    if (i % 100000 == 0)
                        Console.WriteLine(i);
    
                    if (c.IsCancellationRequested)
                    {
                        return ret;
                    }
                }
                return ret;
            });
    }
    

    【讨论】:

    • ?? 来自 CancellationTokenSource
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-25
    • 1970-01-01
    • 1970-01-01
    • 2018-07-24
    • 1970-01-01
    • 2018-05-16
    • 2012-06-11
    相关资源
    最近更新 更多