我有兩個要成對“壓縮”的異步序列,為此我使用Zip了System.Linq.Async包中的運算子。但是,至少對于我而言,該運算子的行為方式并不理想。它不是同時列舉兩個序列,而是按順序列舉它們,結果是延遲加起來。我的每個序列平均每秒鐘發出一個元素,我預計組合序列也會每秒鐘發出 zipped 對,但實際上我每 2 秒得到一對。下面是一個演示此行為的最小示例:
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");
輸出:
(1, 1)
(2, 2)
(3, 3)
(4, 4)
(5, 5)
Duration: 10,155 msec
在 Fiddle 上試試。
有什么方法可以Zip讓程式在 5 秒而不是 10 秒內完成這兩個序列?我對具有理想行為的自定義運算子或官方軟體包中的運算子組合感興趣。
uj5u.com熱心網友回復:
像這樣的東西似乎有效:
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;這里更好。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/405928.html
標籤:
上一篇:當查詢背景關系中不存在where/select時,如何在包含ThenInclude的查詢中指定where和select?
下一篇:后代ID串列-子女、孫子女等
