C# 使用wait&;正确异步

C# 使用wait&;正确异步,c#,async-await,C#,Async Await,我不完全确定我在这里所做的是正确的,因为我没有太多地使用async/await方法,并且将在一个小应用程序中了解更多 代码: 我所做的就是点击一个按钮,导入一个URL列表,检查HTML中的一个字符串,然后返回是或否 目标是在不锁定UI的情况下运行应用程序,我可以使用后台工作程序,但如果按原样运行代码,则会出现错误: 跨线程操作无效:控件“comboBoxPlatform”是从创建它的线程以外的线程访问的 我可以通过调用绕过它,我在正确的轨道上吗 任何帮助都将不胜感激。如错误所述,您正在创建的新线

我不完全确定我在这里所做的是正确的,因为我没有太多地使用async/await方法,并且将在一个小应用程序中了解更多

代码:

我所做的就是点击一个按钮,导入一个URL列表,检查HTML中的一个字符串,然后返回是或否

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

跨线程操作无效:控件“comboBoxPlatform”是从创建它的线程以外的线程访问的

我可以通过调用绕过它,我在正确的轨道上吗


任何帮助都将不胜感激。

如错误所述,您正在创建的新线程无法访问
组合框,因为它未在该新线程中实例化。不过,您对async Wait的想法是正确的

我认为(这只是一种方法)最好的方法是传入
File.ReadAllText(@“Platforms\”+comboBoxPlatform.Text).Split(“|”)
作为参数,这样就不需要在新线程中访问
组合框

private async void BtnImportURLs_Click(object sender, EventArgs e)
{
    string input = @"Platforms\" + comboBoxPlatform.Text).Split('|');
    await Task.Run(() => ImportURLs(input));
}

如错误所述,您正在创建的新线程无法访问
组合框
,因为它未在该新线程中实例化。不过,您对async Wait的想法是正确的

我认为(这只是一种方法)最好的方法是传入
File.ReadAllText(@“Platforms\”+comboBoxPlatform.Text).Split(“|”)
作为参数,这样就不需要在新线程中访问
组合框

private async void BtnImportURLs_Click(object sender, EventArgs e)
{
    string input = @"Platforms\" + comboBoxPlatform.Text).Split('|');
    await Task.Run(() => ImportURLs(input));
}

正如您所说,您需要从UI线程填充组合框。从另一个线程访问它的任何尝试都会导致
CrossThreadException
。我发现最简单的方法是返回任务中的信息,如下所示:

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

    }
专用异步任务GetInformationAsync()
{
var returnList=新列表();
秒表sw=新秒表();
//此时UI线程将释放,没有“真正”的工作
//这样它就不会挂起来了
等待任务。运行(()=>
{
对于(变量i=0;i<10;i++)
{
returnList.Add($“Item{i}”);
//在工作线程上模拟10秒的CPU负载
sw.Restart();
而(从秒(2)开始,经过的时间<时间跨度)
;/*警告此工作线程的100%CPU持续2秒*/
}
});
//在工作线程上运行的任务已完成
//我们把名单还给你
退货清单;
}
私有异步无效按钮1\u单击(对象发送方,事件参数e)
{
//获取一些信息并将其放入列表框
var t=等待GetInformationAsync();
//CPU密集型任务已经完成,我们现在有一个项目列表
//这将在UI线程上运行,没有跨线程异常就证明了这一点
foreach(t中的字符串s)
列表框1.项目。添加;
}
因为能够捕获异常非常重要,这样您就可以知道正在运行的独立任务是否失败以及失败的原因

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

    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!");
        }
    }
专用异步任务GetInformationAsync()
{
var returnList=新列表();
秒表sw=新秒表();
//此时UI线程将释放,没有“真正”的工作
//这样它就不会挂起来了
等待任务。运行(()=>
{
对于(变量i=0;i<10;i++)
{
returnList.Add($“Item{i}”);
//在工作线程上模拟10秒的CPU负载
sw.Restart();
而(从秒(2)开始,经过的时间<时间跨度)
;/*警告此工作线程的100%CPU持续2秒*/
}
//让我们假装上面出了什么问题。。
抛出新的ArgumentNullException(“让我们使用此异常”);
});
//在工作线程上运行的任务已完成
//我们把名单还给你
退货清单;
}
私有异步无效按钮1\u单击(对象发送方,事件参数e)
{
//如果出了问题怎么办我们想抓住例外。。。
//以前的版本不允许我们这样做。。。
尝试
{
var t=等待GetInformationAsync();
//没有引发异常
foreach(t中的字符串s)
列表框1.项目。添加;
}
抓住
{
listBox1.Items.Clear();
listBox1.Items.Add(“出错了!”);
}
}
您可能希望能够做的另一件事是向用户提供进度反馈。对于您提到的调用,显然这是一种老方法。来自许多地方的建议似乎是使用IProgress

下面是一些简单的更改,这些更改会在CPU受限的任务进行时将近乎实时的结果反馈给用户

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

    }
专用异步任务GetInformationAsync(IProgress进程)
{
var returnList=新列表();
秒表sw=新秒表();
//此时UI线程将释放,没有“真正”的工作
//这样它就不会挂起来了
等待任务。运行(()=>
{
对于(变量i=0;i<10;i++)
{
//在工作线程上模拟10秒的CPU负载
sw.Restart();
而(从秒(2)开始,经过的时间<时间跨度)
;/*警告此工作线程的100%CPU持续2秒*/
returnList.Add($“Item{i}”);
//报告回UI线程
//增加进度条。。。
进度报告((i+1)*10);
}
});
//任务