我使用新的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()方法的调用之间的主要区别是什么。
答案 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上下文)。