使用c#5.0调用异步方法

时间:2013-04-22 10:03:53

标签: c# task-parallel-library async-await c#-5.0 synchronizationcontext

我使用新的C#5.0异步模式(async / await)进行一些测试我在理解如何调用异步方法时遇到了问题。

考虑此代码:

private async Task<string> DownloadAsync()
    {
        progress.ProgressChanged += (s, e) =>
            {
                progressBar1.Value = e.value;
            };

            return await DownloadSomething(myurl, progress);

    }

private async void CallDownloadAsync()
    {
        string text = await DownloadAsync();
        progressBar1.Value = 0;
        label1.Text = "Done!";
    }

private void button4_Click(object sender, EventArgs e)
    {
        CallDownloadAsync();
    }

所以,这段代码非常有效。当我点击“button4”时,下载任务开始,我的ProgressBar正确更新。

但是,我想通过删除这样的CallDownloadAsync()方法来压缩我的代码:

private void button4_Click(object sender, EventArgs e)
    {
        new Action(async () =>
        {
            string result = await Task.Run<string>(() => DownloadAsync());
        }).Invoke();
        label1.Text = "Running...";
    }

所以在这里,我想直接启动一个调用DownloadAsync方法的动作,但是当我按下Button4时,我在progressBar上有一个跨线程操作无效。所以我不明白Action()和CallDownloadAsync()方法的调用之间的主要区别是什么。

2 个答案:

答案 0 :(得分:4)

您可能会发现我的async/await intro有帮助。特别是,async方法不在后台线程上运行; Task.Run用于在后台线程上运行某些内容,因此代码中存在差异。

通常,除非您正在编写async void事件处理程序,否则应避免使用async。像这样:

private async void button4_Click(object sender, EventArgs e)
{
    label1.Text = "Running...";
    string result = await DownloadAsync();
    progressBar1.Value = 0;
    label1.Text = "Done!";
}

答案 1 :(得分:1)

不同之处在于,在前一种情况下,您从UI线程(上下文)调用CallDownloadAsync()

在后一种情况下,从发起的Task调用DownloadAsync(),该任务通常在由TPL(任务并行库)创建的不同线程中从UI线程或从其创建的线程中执行。

在WPF中,UI组件只能通过专用UI线程或从其下面创建的(子代)线程访问(即具有相同的UI上下文)。