【发布时间】:2020-01-16 20:59:41
【问题描述】:
我遇到了一些意料之外的行为,我想解释一下。我创建了一个简单的例子来演示这个问题。我使用Task.Run 调用了一个异步函数,它将不断生成结果,并使用IProgress 向UI 传递更新。但我想等到 UI 真正更新后才能继续,所以我尝试使用其他帖子中建议的 TaskCompletionSource(这似乎有点相似:Is it possible to await an event instead of another async method?。)我期待最初的Task.Run 等待,但是什么正在发生的是内部发生的等待似乎将其向前移动,并且“END”在第一次迭代之后发生。 Start() 是入口点:
public TaskCompletionSource<bool> tcs;
public async void Start()
{
var progressIndicator = new Progress<List<int>>(ReportProgress);
Debug.Write("BEGIN\r");
await Task.Run(() => this.StartDataPush(progressIndicator));
Debug.Write("END\r");
}
private void ReportProgress(List<int> obj)
{
foreach (int item in obj)
{
Debug.Write(item + " ");
}
Debug.Write("\r");
Thread.Sleep(500);
tcs.TrySetResult(true);
}
private async void StartDataPush(IProgress<List<int>> progressIndicator)
{
List<int> myList = new List<int>();
for (int i = 0; i < 3; i++)
{
tcs = new TaskCompletionSource<bool>();
myList.Add(i);
Debug.Write("Step " + i + "\r");
progressIndicator.Report(myList);
await this.tcs.Task;
}
}
这样我得到:
BEGIN
Step 0
0
END
Step 1
0 1
Step 2
0 1 2
而不是我想要得到的是:
BEGIN
Step 0
0
Step 1
0 1
Step 2
0 1 2
END
我假设我对 Tasks 和 await 以及它们的工作方式有一些误解。我确实希望 StartDataPush 成为一个单独的线程,我的理解是它是。我的最终用途稍微复杂一些,因为它涉及大量计算、更新到 WPF UI 以及返回它已完成的事件,但机制是相同的。我怎样才能实现我想要做的事情?
【问题讨论】:
-
你不能有意义地等待
async void。让它async Task. -
有一条评论说明为什么
Progress.Report在调用时不会run as expected。我说错了,删了。我认为 我 错了。
标签: c# async-await taskcompletionsource iprogress