首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何同时压缩两个IAsyncEnumerables?

如何同时压缩两个IAsyncEnumerables?
EN

Stack Overflow用户
提问于 2022-01-05 17:02:25
回答 1查看 133关注 0票数 2

我有两个异步序列,我想成对地“压缩”,为此,我使用了System.Linq.Async包中的System.Linq.Async运算符。但是,这个操作符的行为方式并不理想,至少在我的情况下是这样的。它不是同时枚举这两个序列,而是按顺序枚举它们,结果是将延迟加起来。我的每个序列平均每一秒发出一个元素,我预计组合的序列也会每一秒发出一次压缩对,但实际上我每2秒就有一对。下面是一个演示此行为的最小示例:

代码语言:javascript
运行
复制
static async IAsyncEnumerable<int> First()
{
    for (int i = 1; i <= 5; i++) { await Task.Delay(1000); yield return i; }
}

static async IAsyncEnumerable<int> Second()
{
    for (int i = 1; i <= 5; i++) { await Task.Delay(1000); yield return i; }
}

var stopwatch = Stopwatch.StartNew();
await foreach (var pair in First().Zip(Second()))
    Console.WriteLine(pair);
Console.WriteLine($"Duration: {stopwatch.ElapsedMilliseconds:#,0} msec");

输出:

代码语言:javascript
运行
复制
(1, 1)
(2, 2)
(3, 3)
(4, 4)
(5, 5)
Duration: 10,155 msec

在Fiddle上试试

我是否可以用程序在5秒而不是10秒内完成的方式来Zip这两个序列?我对自定义操作符感兴趣,或者对官方包中的操作符组合感兴趣,这些操作符具有理想的行为。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-01-05 17:09:29

像这样的事情似乎奏效了:

代码语言:javascript
运行
复制
public static async IAsyncEnumerable<(TFirst, TSecond)> Zip<TFirst, TSecond>(this IAsyncEnumerable<TFirst> first, IAsyncEnumerable<TSecond> second)
{
    await using var e1 = first.GetAsyncEnumerator();    
    await using var e2 = second.GetAsyncEnumerator();
    
    while (true)
    {
        var t1 = e1.MoveNextAsync().AsTask();
        var t2 = e2.MoveNextAsync().AsTask();
        await Task.WhenAll(t1, t2);
        
        if (!t1.Result || !t2.Result)
            yield break;
        
        yield return (e1.Current, e2.Current);
    }
}

请在dotnetfiddle.net上看到。

当然,这忽略了空检查之类的内容,因此可以通过一些改进来完成:这是留给读者的摘录。

我也不认为Task.WhenAll比这里的bool r1 = await t1; bool r2 = await t2; if (!r1 || !r2) yield break;更好。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70596735

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档