[英]should i choose IAsyncEnumerable<T> or IEnumerable<Task<T>>?
in my C# program, I have a list that has 100+ URLs and I will download files from those URLs.在我的 C# 程序中,我有一个包含 100 多个 URL 的列表,我将从这些 URL 下载文件。
at first, I will use list.select(x=> DosomethingAsync(x))
then use Task.WhenAny
to handle the result (these step is very fast, the main cost is file download)首先,我会使用
list.select(x=> DosomethingAsync(x))
然后使用Task.WhenAny
来处理结果(这一步非常快,主要成本是文件下载)
while (!itemsTasks.IsNullOrEmpty())
{
Task<Stream> fininshed_item_task = await Task.WhenAny(itemsTasks);
Stream itemResult = await fininshed_item_task;
// do something with itemResult
......
itemsTasks.Remove(fininshed_item_task);
}
now I hear that there is IAsyncEnumerable and it seems could keep my code more straightforward.现在我听说有 IAsyncEnumerable,它似乎可以让我的代码更简单。
but I am very worried IAsyncEnumerable will fetch file one by one and cost more time.但我很担心 IAsyncEnumerable 会一个一个地获取文件并花费更多时间。 And I find that
IAsyncEnumerable
do a lot of thread changing!而且我发现
IAsyncEnumerable
做了很多线程更改!
IEnumerable<Task<T>>
seems to start tasks immediately before await. IEnumerable<Task<T>>
似乎在等待之前立即开始任务。 and another problem is I need to find a way to cancel the remaining tasks if there is one get failed.另一个问题是如果有一个失败,我需要找到一种方法来取消剩余的任务。
Can you explain this?你能解释一下吗?
Basically IAsyncEnumerable
is an enumeration of awaited tasks' result while IEnumerable<Task>
is an enumeration of tasks.基本上
IAsyncEnumerable
是等待任务结果的枚举,而IEnumerable<Task>
是任务的枚举。
I would say that IAsynEnumerable
is a shortcut feature for a specific usecase of IEnumerable<Task<T>>
.我会说
IAsynEnumerable
是IEnumerable<Task<T>>
特定用例的快捷功能。
Let's say we have this expensive operation to perform假设我们要执行这个昂贵的操作
static async Task<int> ExpensiveOperationAsync(int number)
{
// some expensive operation
await Task.Delay(100);
return number;
}
To return the operation's result on all of the positives numbers you obviously could not just return a list of values since there is an infinite amount of them, so you would have to yield every result once the task has completed.要返回所有正数的操作结果,您显然不能只返回一个值列表,因为它们的数量是无限的,因此一旦任务完成,您就必须产生每个结果。
But this does not compile since int
is not awaitable and the method is async
.但这不会编译,因为
int
是不可等待的并且方法是async
。
static async int GetNumbersAsync()
{
var i = 0;
while (true)
{
yield return await ExpensiveOperationAsync(i++);
}
}
One way around is to not use an aync
method and just return the tasks, here we have our IEnumerable<Task<int>>
.一种解决方法是不使用
aync
方法而只返回任务,这里我们有我们的IEnumerable<Task<int>>
。
static IEnumerable<Task<int>> GetNumbersAsyncEnumerableTasks()
{
var i = 0;
while (true)
{
yield return ExpensiveOperationAsync(i++);
}
}
And use it并使用它
foreach (var task in GetNumbersAsyncEnumerableTasks())
Console.WriteLine(await task);
But one downside of this approach is that it's not very explicit about what you are trying to achieve.但是这种方法的一个缺点是它对你想要实现的目标不是很明确。
Instead C# provides a nicer way to do this, the IAsyncEnumerable<T>
which is a kind of an awaitable thing.相反,C# 提供了一种更好的方法来执行此操作,即
IAsyncEnumerable<T>
,它是一种可等待的东西。
static async IAsyncEnumerable<int> GetNumbersAsyncEnumerable(int max)
{
for (var i = 0; i < max + 1; i++)
{
yield return await ExpensiveOperationAsync(i);
}
}
// notice the await foreach syntax
await foreach (var number in GetNumbersAsyncEnumerable(10))
Console.WriteLine(number);
As you can see IAsynEnumerable<T>
is useful for a few specific situations but it does not seem to fit your case.如您所见
IAsynEnumerable<T>
对于一些特定情况很有用,但它似乎不适合您的情况。
I rather do something like this我宁愿做这样的事情
public class MyProcessor
{
public async Task ProcessAllTasksAsync<T>(IEnumerable<Task<T>> tasks)
{
var wrappedTasks = tasks.Select(TaskWrapperAsync);
await Task.WhenAll(wrappedTasks);
}
private async Task TaskWrapperAsync<T>(Task<T> task)
{
var result = await task;
DoSomethingWithItemResult(result);
}
private void DoSomethingWithItemResult<T>(T result)
{
// some cool stuff
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.