我没有找到合适的话题,也许我看起来很糟糕,但尽管如此。也许有人挖了这样一个话题。这是一个高负载的应用程序,我想尽可能地优化它。特别是,它包含以下代码片段:
{
var items = GetItemsFromSomethere();
await SomeAsyncFunction(items);
// ...
}
async Task SomeAsyncFunction(ICollection<T> items)
{
var filteredItems = await SomeAsyncFilter(items);
await AnotherAsyncFunction(filteredItems);
// и т.д., там и дальше могут ещё быть цепочки асинхронных вызовов
}
所以这就是问题所在。调用所有这些异步函数时是否有很大的开销——毕竟state machine每次调用都会创建等等。同时,我确信它经常会SomeAsyncFunction返回一个空集合,并且它被频繁调用,并且可以通过简单地检查集合是否为空来避免调用整个异步函数链在调用函数之前。
{
var items = GetItemsFromSomethere();
if(items.Count > 0)
{
await SomeAsyncFunction(items);
}
// ...
}
async Task SomeAsyncFunction(ICollection<T> items)
{
var filteredItems = await SomeAsyncFilter(items);
if(filteredItems.Count > 0)
{
await AnotherAsyncFunction(filteredItems);
// и т.д., там и дальше могут ещё быть цепочки асинхронных вызовов
}
}
似乎可以毫不犹豫地在代码中的任何地方执行此操作,但如果它没有给出任何东西怎么办,那么为什么要通过一些额外的结构来复杂化和膨胀代码呢?我想了解-至少在理论上,我会用这种方法节省一些东西吗?当然,这将取决于集合多久是空的,异步函数的链有多长等,但至少大致和概括地说,我想理解这个话题。其次,也许有某种语法糖可以进行这样的检查,而不会用不必要的结构重载代码(以防最好在代码中添加这样的检查)?谢谢你。
PS 至于同步函数,据我了解,空集合的额外函数调用的成本不会那么大 - 将对集合的引用放在堆栈上,然后调用函数。不过,不state machine,它更容易。但如果有任何关于同步函数主题的食谱,我会很高兴地听他们说。
更新:更正void,Task添加var-我是凭记忆写的,我错了。关于最快检查通过的事实items.Count != 0-消失的答案中写得很正确,只是这种检查的形式在我看来不如items.Any(). 但是为了优化,显然,如果我决定仍然进行检查,我将不得不这样做。此外,我检查了代码 -ICollection尽管如此,我必须检查它Count,它没有Any()。
结果,他自己进行了原始基准测试,结果总体上符合预期 - 有效果,但仅在大量执行此类代码时才明显。
我通过
Task.WhenAll异步/等待链并行执行 1,000,000(百万)个任务来检查它,实际上什么都不做,只是简单地将控制权传递给彼此(就像在空集合的情况下一样)。在始终为空集合的情况下运行时:
好吧,也就是说,仍然有一些影响,但是在执行大量任务和纯粹总是空的集合时会很明显。
条件再复杂一点。现在在 50% 的情况下,集合是空的,在 50% 的情况下,有 100 个元素,它们只是通过 foreach 添加到新列表中并返回。
自然,整个测试执行时间增加了,效果也更加模糊:
通常,通过这种方式可以节省一些资源,但一切都取决于输入中空/非空集合的数量之比以及函数内部集合执行的计算量。这样一来,您将无法节省很多。
我想只有代码分析才能给出准确的答案。
其他都是读卡。
一般来说,添加这样的检查会破坏代码。
如果 items 集合为空,则不会调用 SomeAsyncFunction。但是,即使存在空集合,它也可能正在执行一些重要的操作。副作用很糟糕,但仍然...
如果我们知道 SomeAsyncFunction 的内部结构并且知道它可以被安全地排除,那么这违背了良好的编程习惯。对象应该像黑盒子一样对待。我们不需要知道他们的设备。
当然,当涉及到高负载的代码时,好的实践和模式会逐渐消失。