gpt4 book ai didi

c# - 等待和继续之间的区别

转载 作者:IT王子 更新时间:2023-10-29 03:35:21 24 4
gpt4 key购买 nike

谁能解释一下 awaitContinueWith 在下面的例子中是否是同义词。我是第一次尝试使用 TPL,并且已经阅读了所有文档,但不明白其中的区别。

等待:

String webText = await getWebPage(uri);
await parseData(webText);

继续:

Task<String> webText = new Task<String>(() => getWebPage(uri));
Task continue = webText.ContinueWith((task) => parseData(task.Result));
webText.Start();
continue.Wait();

在特定情况下,一个比另一个更受欢迎吗?

最佳答案

这是我最近用来说明差异和使用异步解决的各种问题的代码片段序列。

假设您在基于 GUI 的应用程序中有一些需要花费大量时间的事件处理程序,因此您希望将其设为异步。这是您开始使用的同步逻辑:

while (true) {
string result = LoadNextItem().Result;
if (result.Contains("target")) {
Counter.Value = result.Length;
break;
}
}

LoadNextItem 返回一个任务,它最终会产生一些您想要检查的结果。如果当前结果是您要查找的结果,则更新 UI 上某个计数器的值,然后从该方法返回。否则,您将继续处理来自 LoadNextItem 的更多项目。

异步版本的第一个想法:只使用延续!让我们暂时忽略循环部分。我的意思是,可能会出现什么问题?

return LoadNextItem().ContinueWith(t => {
string result = t.Result;
if (result.Contains("target")) {
Counter.Value = result.Length;
}
});

太好了,现在我们有了一个不会阻塞的方法!它反而崩溃了。对 UI 控件的任何更新都应该发生在 UI 线程上,因此您需要考虑到这一点。值得庆幸的是,有一个选项可以指定如何安排延续,并且有一个默认选项:

return LoadNextItem().ContinueWith(t => {
string result = t.Result;
if (result.Contains("target")) {
Counter.Value = result.Length;
}
},
TaskScheduler.FromCurrentSynchronizationContext());

太好了,现在我们有了一个不会崩溃的方法!相反,它默默地失败了。后续任务本身是独立的任务,其状态与先前任务的状态无关。因此,即使 LoadNextItem 出错,调用者也只会看到已成功完成的任务。好的,如果有的话,就传递异常:

return LoadNextItem().ContinueWith(t => {
if (t.Exception != null) {
throw t.Exception.InnerException;
}
string result = t.Result;
if (result.Contains("target")) {
Counter.Value = result.Length;
}
},
TaskScheduler.FromCurrentSynchronizationContext());

太棒了,现在这真的有用了。对于单个项目。现在,循环怎么样。事实证明,与原始同步版本的逻辑等效的解决方案将如下所示:

Task AsyncLoop() {
return AsyncLoopTask().ContinueWith(t =>
Counter.Value = t.Result,
TaskScheduler.FromCurrentSynchronizationContext());
}
Task<int> AsyncLoopTask() {
var tcs = new TaskCompletionSource<int>();
DoIteration(tcs);
return tcs.Task;
}
void DoIteration(TaskCompletionSource<int> tcs) {
LoadNextItem().ContinueWith(t => {
if (t.Exception != null) {
tcs.TrySetException(t.Exception.InnerException);
} else if (t.Result.Contains("target")) {
tcs.TrySetResult(t.Result.Length);
} else {
DoIteration(tcs);
}});
}

或者,您可以使用 async 来做同样的事情,而不是上面所有的事情:

async Task AsyncLoop() {
while (true) {
string result = await LoadNextItem();
if (result.Contains("target")) {
Counter.Value = result.Length;
break;
}
}
}

现在好多了,不是吗?

关于c# - 等待和继续之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18965200/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com