简体   繁体   English

我应该选择 IAsyncEnumerable<T> 或 IEnumerable <Task<T> &gt;?

[英]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>> .我会说IAsynEnumerableIEnumerable<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.

相关问题 我可以(或应该)使用 IAsyncEnumerable<T> 而不是任务<ActionResult<IEnumerable<T> &gt;&gt; 在 Web API 控制器中 - Can (or should) I use IAsyncEnumerable<T> instead of Task<ActionResult<IEnumerable<T>>> in a Web API Controller 我怎样才能“适应”一个任务<ienumerable<t> &gt; 到 IAsyncEnumerable<t> ? </t></ienumerable<t> - How can I "adapt" a Task<IEnumerable<T>> to IAsyncEnumerable<T>? IAsyncEnumerable 有什么区别<T>与 IEnumerable <Task<T> &gt;? - Whats the difference between IAsyncEnumerable<T> vs IEnumerable<Task<T>>? IAsyncEnumerable 和有什么区别<t>和一个迭代器生成的 IEnumerable <task<t> &gt;? </task<t></t> - What's the difference between IAsyncEnumerable<T> and an iterator-generated IEnumerable<Task<T>>? 来自 IEnumerable <task<t> &gt; 到 IAsyncEnumerable<t> 通过 yield 在 Parallel.ForEach/Parallel.ForEachAsync 中返回会给出错误 CS1621 </t></task<t> - From IEnumerable<Task<T>> to IAsyncEnumerable<T> by yield returning inside a Parallel.ForEach/Parallel.ForEachAsync gives error CS1621 转换任务 <DbSet<T> &gt;到任务 <IEnumerable<T> &gt; - Converting Task<DbSet<T>> to Task<IEnumerable<T>> 为什么使用 IAsyncEnumerable 比返回 async/await 任务慢<T> ? - Why is using IAsyncEnumerable slower than returning async/await Task<T>? 如何等待 IAsyncEnumerable 的结果<Task<T> &gt;,具有特定的并发级别 - How to await the results of an IAsyncEnumerable<Task<T>>, with a specific level of concurrency 我应该总是返回 IEnumerable<t> 而不是 IList<t> ?</t></t> - Should I always return IEnumerable<T> instead of IList<T>? 异步迭代器任务<IEnumerable<T> &gt; - Asynchronous iterator Task<IEnumerable<T>>
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM