- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我一直在关注this question我理解 Peter Duniho 的流行(尽管尚未被接受)答案背后的原因.具体来说,我知道不等待后续长时间运行的操作会阻塞 UI 线程:
The second example does not yield during the asynchronous operation. Instead, by getting the value of the content.Result property, you force the current thread to wait until the asynchronous operation has completed.
为了我自己的利益,我什至已经确认了这一点,就像这样:
private async void button1_Click(object sender, EventArgs e)
{
var value1 = await Task.Run(async () =>
{
await Task.Delay(5000);
return "Hello";
});
//NOTE: this one is not awaited...
var value2 = Task.Run(async () =>
{
await Task.Delay(5000);
return value1.Substring(0, 3);
});
System.Diagnostics.Debug.Print(value2.Result); //thus, UI freezes here after 5000 ms.
}
但现在我想知道:您是否需要 await
嵌套在最外层可等待操作中的所有“可等待”操作?例如,我可以这样做:
private async void button1_Click(object sender, EventArgs e)
{
var value0 = await Task.Run(() =>
{
var value1 = new Func<Task<string>>(async () =>
{
await Task.Delay(5000);
return "hello";
}).Invoke();
var value2 = new Func<string, Task<string>>(async (string x) =>
{
await Task.Delay(5000);
return x.Substring(0, 3);
}).Invoke(value1.Result);
return value2;
});
System.Diagnostics.Debug.Print(value0);
}
或者我可以这样做:
private async void button1_Click(object sender, EventArgs e)
{
//This time the lambda is async...
var value0 = await Task.Run(async () =>
{
//we're awaiting here now...
var value1 = await new Func<Task<string>>(async () =>
{
await Task.Delay(5000);
return "hello";
}).Invoke();
//and we're awaiting here now, too...
var value2 = await new Func<string, Task<string>>(async (string x) =>
{
await Task.Delay(5000);
return x.Substring(0, 3);
}).Invoke(value1);
return value2;
});
System.Diagnostics.Debug.Print(value0);
}
而且它们都不会卡住 UI。哪个更好?
最佳答案
最后一个比较好(虽然比较乱)
在 TAP(基于任务的异步模式)中,任务(和其他可等待对象)表示异步操作。您基本上有 3 个选项来处理这些任务:
DoAsync().Result
, DoAsync().Wait()
) - 在任务完成之前阻塞调用线程。使您的应用程序更加浪费,可扩展性更差,响应更慢并且容易出现死锁。 await DoAsync()
) - 不阻塞调用线程。它基本上将 await
之后的工作注册为等待任务完成后要执行的延续。DoAsync()
) - 不阻塞调用线程,也不等待操作完成。您不知道在处理 DoAsync
时抛出的任何异常Specifically, I am aware that not awaiting a subsequent long-running operation will block the UI thread
所以,不完全是。如果你根本不等待,什么都不会阻塞,但你无法知道操作何时或是否成功完成。但是,如果您同步等待,您将阻塞调用线程,并且如果您阻塞 UI 线程,则可能会出现死锁。
结论:您应该尽可能地await
您的可等待对象(例如,它不在Main
中)。这包括“嵌套的 async-await
操作”。
关于您的具体示例:Task.Run
用于将 CPU 密集型工作卸载到 ThreadPool
线程,这似乎不是您想要的模仿。如果我们使用 Task.Delay
来表示真正的异步操作(通常是 I/O 绑定(bind)),我们可以在没有 Task.Run 的情况下使用“嵌套的
:async-await
”
private async void button1_Click(object sender, EventArgs e)
{
var response = await SendAsync();
Debug.WriteLine(response);
}
async Task<Response> SendAsync()
{
await SendRequestAsync(new Request());
var response = await RecieveResponseAsync();
return response;
}
async Task SendRequestAsync(Request request)
{
await Task.Delay(1000); // actual I/O operation
}
async Task<Response> RecieveResponseAsync()
{
await Task.Delay(1000); // actual I/O operation
return null;
}
您可以使用匿名委托(delegate)而不是方法,但是当您需要定义类型并自己调用它们时,这会很不方便。
如果您确实需要将该操作卸载到 ThreadPool
线程,只需添加 Task.Run
:
private async void button1_Click(object sender, EventArgs e)
{
var response = await Task.Run(() => SendAsync());
Debug.WriteLine(response);
}
关于c# - 是否应该等待嵌套的可等待操作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28221385/
我有一个 if 语句,如下所示 if (not(fullpath.lower().endswith(".pdf")) or not (fullpath.lower().endswith(tup
然而,在 PHP 中,可以: only appears if $foo is true. only appears if $foo is false. 在 Javascript 中,能否在一个脚
XML有很多好处。它既是机器可读的,也是人类可读的,它具有标准化的格式,并且用途广泛。 它也有一些缺点。它是冗长的,不是传输大量数据的非常有效的方法。 XML最有用的方面之一是模式语言。使用模式,您可
由于长期使用 SQL2000,我并没有真正深入了解公用表表达式。 我给出的答案here (#4025380)和 here (#4018793)违背了潮流,因为他们没有使用 CTE。 我很欣赏它们对于递
我有一个应用程序: void deleteObj(id){ MyObj obj = getObjById(id); if (obj == null) { throw n
我的代码如下。可能我以类似的方式多次使用它,即简单地说,我正在以这种方式管理 session 和事务: List users= null; try{ sess
在开发J2EE Web应用程序时,我通常会按以下方式组织我的包结构 com.jameselsey.. 控制器-控制器/操作转到此处 服务-事务服务类,由控制器调用 域-应用程序使用的我的域类/对象 D
这更多是出于好奇而不是任何重要问题,但我只是想知道 memmove 中的以下片段文档: Copying takes place as if an intermediate buffer were us
路径压缩涉及将根指定为路径上每个节点的新父节点——这可能会降低根的等级,并可能降低路径上所有节点的等级。有办法解决这个问题吗?有必要处理这个吗?或者,也许可以将等级视为树高的上限而不是确切的高度? 谢
我有两个类,A 和 B。A 是 B 的父类,我有一个函数接收指向 A 类型类的指针,检查它是否也是 B 类型,如果是将调用另一个函数,该函数接受一个指向类型 B 的类的指针。当函数调用另一个函数时,我
有没有办法让 valgrind 使用多个处理器? 我正在使用 valgrind 的 callgrind 进行一些瓶颈分析,并注意到我的应用程序中的资源使用行为与在 valgrind/callgrind
假设我们要使用 ReaderT [(a,b)]超过 Maybe monad,然后我们想在列表中进行查找。 现在,一个简单且不常见的方法是: 第一种可能性 find a = ReaderT (looku
我的代码似乎有问题。我需要说的是: if ( $('html').attr('lang').val() == 'fr-FR' ) { // do this } else { // do
根据this文章(2018 年 4 月)AKS 在可用性集中运行时能够跨故障域智能放置 Pod,但尚不考虑更新域。很快就会使用更新域将 Pod 放入 AKS 中吗? 最佳答案 当您设置集群时,它已经自
course | section | type comart2 : bsit201 : lec comart2 :
我正在开发自己的 SDK,而这又依赖于某些第 3 方 SDK。例如 - OkHttp。 我应该将 OkHttp 添加到我的 build.gradle 中,还是让我的 SDK 用户包含它?在这种情况下,
随着 Rust 越来越充实,我对它的兴趣开始激起。我喜欢它支持代数数据类型,尤其是那些匹配的事实,但是对其他功能习语有什么想法吗? 例如标准库中是否有标准过滤器/映射/归约函数的集合,更重要的是,您能
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 关闭 9 年前。 Improve
我一直在研究 PHP 中的对象。我见过的所有示例甚至在它们自己的对象上都使用了对象构造函数。 PHP 会强制您这样做吗?如果是,为什么? 例如: firstname = $firstname;
...比关联数组? 关联数组会占用更多内存吗? $arr = array(1, 1, 1); $arr[10] = 1; $arr[] = 1; // <- index is 11; does the
我是一名优秀的程序员,十分优秀!