使用等待和正确异步 [英] Using Await & Async Properly

查看:50
本文介绍了使用等待和正确异步的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不确定我在这里做什么是正确的,因为我没有使用太多async/await方法,而是打算在一个小型应用程序中学习更多.

I'm not entirely sure what I am doing here is correct as I haven't used the async / await methods much and was going to learn more in a small application.

代码:

        public async Task ImportURLs() {

            // read contents of the chosen combobox platform ...
            var comp = File.ReadAllText(@"Platforms\" + comboBoxPlatform.Text).Split('|');
            var reg = comp[0];
            var fl1 = comp[1];
            var fl2 = comp[2];

            string line;
            OpenFileDialog ofd = new OpenFileDialog
            {
                Filter = "URLs.txt|*.txt"
            };
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                if (ofd.FileName.Trim() != string.Empty)
                {
                    using (StreamReader r = new StreamReader(ofd.FileName))
                    {
                        while ((line = r.ReadLine()) != null)
                        {
                            // check fl1 exists in the url first ...
                            var check_1 = Helpers.FindNeedleInHtml(line, fl1);

                            // if it does the root the url and check the reg page ...
                            if (check_1 == "Yes")
                            {
                                var check_2 = Helpers.FindNeedleInHtml(line, fl2);
                                // check_ & check_2 is "Yes" or "No"
                                AddToListView(Helpers.GetRootUrl(line) + reg, check_1, check_2);
                            }

                        }
                    }
                }
            }
        }

        private async void BtnImportURLs_Click(object sender, EventArgs e)
        {
            await Task.Run(() => ImportURLs());
        }

我要做的就是单击一个按钮并导入URL列表,检查HTML中的字符串,然后报告是或否.

All I'm doing is clicking a button and importing a list of URLs, checking a string in the HTML then reporting back a Yes or No.

目标是在不锁定UI的情况下运行应用程序,我可以使用后台工作程序,但是如果按原样运行代码,则会出现错误:

The goal was to run the application without locking the UI up and I could use a background worker, but if I run the code as it is I get the error:

跨线程操作无效:控制'comboBoxPlatform'是从创建该线程的线程之外的其他线程访问的.

Cross-thread operation not valid: Control 'comboBoxPlatform' accessed from a thread other than the thread it was created on.

我可以通过调用绕过哪些方向,我走在正确的轨道上吗?

Which I could bypass by Invoking, am I on the right track?

任何帮助将不胜感激.

推荐答案

正如您所说,您需要从UI线程中填充comboBox.从另一个线程访问它的任何尝试都会给您CrossThreadException.我发现执行此操作最简单的方法是从Task中返回信息,如下所示:

As you say, you need to populate the comboBox from the UI thread. Any attempt to access it from another thread will give you the CrossThreadException. The easiest way I have found to do this is to return the information from the Task like this:

    private async Task<List<string>> GetInformationAsync()
    {
        var returnList = new List<string>();
        Stopwatch sw = new Stopwatch();

        // The UI thread will free up at this point, no "real" work has
        // started so it won;t have hung
        await Task.Run(() =>
        {
            for (var i = 0; i < 10; i++)
            {
                returnList.Add($"Item# {i}");

                // Simulate 10 seconds of CPU load on a worker thread
                sw.Restart();
                while (sw.Elapsed < TimeSpan.FromSeconds(2))
                    ; /* WARNING 100% CPU for this worker thread for 2 seconds */
            }
        });

        // Task that was running on the Worker Thread has completed
        // we return the List<string>

        return returnList;
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        // Get some information and put this into the listBox

        var t = await GetInformationAsync();

        // The CPU intensive task has completed we now have a list of items
        // This will run on the UI thread, as evidenced by no Cross Thread exception
        foreach (string s in t)
            listBox1.Items.Add(s);

    }

因为能够捕获异常非常重要,所以您可以知道正在运行的独立任务是否失败以及失败的原因.

And because it's important to be able to catch exceptions so you know if the independent task that was running failed and why it failed.

与上述代码相同,但具有一些简单的异常处理.

Same code as above but with some simple exception handling.

    private async Task<List<string>> GetInformationAsync()
    {
        var returnList = new List<string>();
        Stopwatch sw = new Stopwatch();

        // The UI thread will free up at this point, no "real" work has
        // started so it won;t have hung
        await Task.Run(() =>
        {

            for (var i = 0; i < 10; i++)
            {
                returnList.Add($"Item# {i}");

                // Simulate 10 seconds of CPU load on a worker thread
                sw.Restart();
                while (sw.Elapsed < TimeSpan.FromSeconds(2))
                    ; /* WARNING 100% CPU for this worker thread for 2 seconds */
            }

            // Lets pretend that something went wrong up above..
            throw new ArgumentNullException("Lets use this exception");

        });

        // Task that was running on the Worker Thread has completed
        // we return the List<string>

        return returnList;
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        // What if something went wrong we want to catch the exception...
        // the previous verion doesn;t let us do that...

        try
        {
            var t = await GetInformationAsync();

            // No exception was thrown
            foreach (string s in t)
                listBox1.Items.Add(s);
        }
        catch
        {
            listBox1.Items.Clear();
            listBox1.Items.Add("Something went wrong!");
        }
    }

您可能想做的另一件事是向用户提供进度反馈.为此,您提到了Invoke-显然,这是旧方法.来自许多地方的建议似乎是使用IProgress.

The other thing you might like to be able to do, is to provide feedback of progress to the user. For that you mentioned Invoke - apparently that's the old way of doing it. The suggestion from a number of places seems to be to use an IProgress.

这里有一些简单的更改,随着CPU绑定任务的进行,这些更改将近乎实时的结果反馈给用户.

Here are some simple changes that feed near realtime results back to the user as the CPU bound Task progresses.

    private async Task<List<string>> GetInformationAsync(IProgress<int> progress)
    {
        var returnList = new List<string>();
        Stopwatch sw = new Stopwatch();

        // The UI thread will free up at this point, no "real" work has
        // started so it won;t have hung
        await Task.Run(() =>
        {

            for (var i = 0; i < 10; i++)
            {
                // Simulate 10 seconds of CPU load on a worker thread
                sw.Restart();
                while (sw.Elapsed < TimeSpan.FromSeconds(2))
                    ; /* WARNING 100% CPU for this worker thread for 2 seconds */

                returnList.Add($"Item# {i}");

                // Report back to the UI thread
                // increases the progress bar...
                progress.Report((i+1)*10);
            }
        });

        // Task that was running on the Worker Thread has completed
        // we return the List<string>

        return returnList;
    }

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

        button1.Enabled = false;

        try
        {
            var progress = new Progress<int>(i => progressBar1.Value = i);

            var t = await GetInformationAsync(progress);

            // No exeception was thrown
            foreach (string s in t)
                listBox1.Items.Add(s);
        }
        catch
        {
            listBox1.Items.Clear();
            listBox1.Items.Add("Something went wrong!");
        }
        finally
        {
            button1.Enabled = true;
        }

    }

这篇关于使用等待和正确异步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆