Здравствуйте, VladCore, Вы писали:
VC>накладные расходы легко посчитать:
VC>1. если под await сеть, то сравнить await foreach и foreach для TcpListener на localhost и 127.0.0.1. разница будет потому что MTA разный
VC>2. если под await диск, то сравнить await foreach и foreach для RAM-диска или оптан диска.
VC>3. если под await потоки (например ManualResetEventSlim.Wait — самая быстрая реализация) то я уже делился задержками. Они большие: 1 микросекунда в Core на Windows, 2 — Core на линукс, 4 — на NetFramework и 16 — в моно. на кажую итерацию. Это всё на Intel Xeon 6го поколения.
Ок, я, кажется, понял, что нужно делать.
Вот нашёл прямо-таки идеально совпадающий с моими размышлениями
пример:
public async IAsyncEnumerable<Product> GetAllProducts()
{
var iterator = cosmosClient.GetContainer(DatabaseId, ContainerId).GetItemQueryIterator<Product>("SELECT * FROM c");
while (iterator.HasMoreResults)
foreach (var product in await iterator.ReadNextAsync())
yield return product;
}
Тут как раз на входе — набор
страниц, на выходе — плоский IAsyncEnumerable.
В случае, если GetItemQueryIterator<Product> возвращает нам ровно один FeedResponse<Product>, то это всё вырождается в линейный код типа такого:
public async IAsyncEnumerable<Product> GetAllProducts()
{
foreach (var product in await iterator.ReadNextAsync())
yield return product;
}
Тут нам не очень важен внутренний await.
Можно просто построить асинхронный стрим:
public static async IAsyncEnumerable<T> ToAsync(this IEnumerable<T> enumerable)
{
foreach(var t in enumerable) yield return t;
}
После этого можно сравнить что-нибудь простое, типа вычисления суммы массива синхронно и асинхронно:
public async Task<int> SumSync(IEnumerable<int> enumerable)
{
var s = 0;
foreach(var i in enumerable) s+=i;
return s;
}
public async Task<int> SumAsync(IEnumerable<int> enumerable)
{
var s = 0;
await foreach(var i in enumerable.ToAsync()) s+=i;
return s;
}
Передаём на вход массивы целых различной длины, можно прикинуть расходы на итерацию.
Надо нарисовать бенчмарку.