Здравствуйте, Sharov, Вы писали:
S>>>А классический sql бд не могут батчами данные гнать, ну т.е. данных до фига, канал не резиновый, загнали 1Гб, S>>>получили все возможные Person, прочитали, подогнали еще 1Гб данных и т.д. Это как раз про то, что выше говорилось -- S>>>IEnumerable<Task<IEnumerable<T>>>. Т.е. сценарий NoSql понятен, но вот когда реально много данных и все сразу в память S>>>не прочитаешь тоже сюда относится.
VC>>Классический SQL клиент никогда не грузит в память весь 1Гб и на сервере иногда "грузит" весь возвращаемый набор иногда нет.
VC>>
VC>>SqlConnection con = ;
VC>>var persons = await con.QueryAsync<Person>("Select * From Person Order By Surname");
VC>>foreach(Person p in persons) {
VC>>}
VC>>
VC>>вот тут весь 1 гигабайт на клиенте всегда НЕ грузится целиком в озу.
S>А почему нет, если памяти хватает. Речь о случае, когда у нас памяти мало и мы не можем целиком все загрузить. S>А когда памяти хватат, почему бы все сразу не загрузить?
есть Managed объекты в памяти, есть память в ОС процесса, её еще называют кучей. это разные вещи. я не понимаю о какой памяты ты сейчас говориш в контексте того что мой пример съест в куче 1 гиг озу и сразу пометит её для сборки мусора если ОЗУ достаточно.
S>В любом случае, речь о том, где будут данные между
S>var persons = await con.QueryAsync<Person>("Select * From Person Order By Surname"); S>и S>foreach(Person p in persons)
нигде. здесь persons это запрос, а не то что он возвращает.
S>Как я понимаю, когда мы уже итерируемся по persons, то мы получили все данные от сервера, где S>бы на клиенте они не находились. Я же говорил, про возможность итерироваться по полученным S>persons, когда мы получаем только часть данных. Т.е. что-то получили, десериализовали, прошлись циклом, S>читаем сл. порцию и т.д.
S>Т.е. в одном случае (как в примере выше) foreach начнет работу после окончания работы сервера, S>а возможен ли случай, когда foreach начнет работу параллельно с работой сервера?
это оно и есть. Полностью загрузить это persons.ToList();
Здравствуйте, VladCore, Вы писали: VC>это издержки горизонтально масштабируемего NoSQL хранилища. клиенское API подогнано под тот факт что одним запросом всё нельзя получить что попадает под фильтр.
Как по мне — так это попытка объяснить через объясняемое. Ну, то есть звучит убедительно, но внезапно поддержка постраничного доступа является не только популярной модой, но и частью, к примеру, стандарта OData.
Независимо от того, лежит ли под источником NoSQL или SQL.
С т.з. номенклатуры типов дотнет, ODATA выглядит как IEnumerable<IList<T>>.
А если мы выгребаем его асинхронно — то как IEnumerable<Task<IList<T>>>.
Вот я как раз и размышляю над тем, что нужно выставлять наружу из источника потенциально больших данных. IEnumerable<Task<IList<T>>> — ну, такое себе решение.
IAsyncEnumerable<T> выглядит эстетичной альтернативой.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>>А почему нет, если памяти хватает. Речь о случае, когда у нас памяти мало и мы не можем целиком все загрузить. S>>А когда памяти хватат, почему бы все сразу не загрузить? VC>есть Managed объекты в памяти, есть память в ОС процесса, её еще называют кучей. это разные вещи. я не понимаю о какой памяты ты сейчас говориш в контексте того что мой пример съест в куче 1 гиг озу и сразу пометит её для сборки мусора если ОЗУ достаточно.
Я про память процесса.
S>>В любом случае, речь о том, где будут данные между S>>var persons = await con.QueryAsync<Person>("Select * From Person Order By Surname"); S>>и S>>foreach(Person p in persons) VC>нигде. здесь persons это запрос, а не то что он возвращает.
Чет я потерялся: я понимаю про eager\lazy loading (ienumarable\iquarable в контексте бд), но зачем
тогда await, если это будет просто установка соединения с бд? Т.к. времени на получение и обработку
persons явно будет затрачено больше(continuation). Ну с др. стороны установка соединения тоже io, так что скорее
всего имеет смысл. Тогда все более менее понятно, за остальными деталями к драйверу бд.
S>>Т.е. в одном случае (как в примере выше) foreach начнет работу после окончания работы сервера, S>>а возможен ли случай, когда foreach начнет работу параллельно с работой сервера? VC>это оно и есть. Полностью загрузить это persons.ToList();
Здравствуйте, Sinclair, Вы писали:
S>С т.з. номенклатуры типов дотнет, ODATA выглядит как IEnumerable<IList<T>>. S>А если мы выгребаем его асинхронно — то как IEnumerable<Task<IList<T>>>.
S>Вот я как раз и размышляю над тем, что нужно выставлять наружу из источника потенциально больших данных. IEnumerable<Task<IList<T>>> — ну, такое себе решение. S>IAsyncEnumerable<T> выглядит эстетичной альтернативой.
Мне кажется, что постраничный доступ хорошо бы смотрелся через IAsyncEnumerable<IList<T>>, потому как у нас уже есть возможность обращаться к MoveNext асинхронно. Мы не знаем, будет ли еще страница в результате. А IEnumerable<Task<IList<T>>> говорит о том, что ответ на вопрос будет ли еще страница мы можем получить лишь синхронно.
Здравствуйте, samius, Вы писали: S>Мне кажется, что постраничный доступ хорошо бы смотрелся через IAsyncEnumerable<IList<T>>, потому как у нас уже есть возможность обращаться к MoveNext асинхронно. Мы не знаем, будет ли еще страница в результате. А IEnumerable<Task<IList<T>>> говорит о том, что ответ на вопрос будет ли еще страница мы можем получить лишь синхронно.
Да, верно. А не завернуть ли нам чтение из такого источника в хелпер?
Типа вместо
await foreach(var page in db.GetPages<Product>(...))
foreach(var p in pages)
this.Writer.Write(p);
? Хотя, в целом даже и первый вариант выглядит не слишком отвратительно.
В общем, я себе в план работ поставил напиливание бенчмарка IAsyncEnumerable<T> супротив IEnumerable<T> и IAsyncEnumerable<IList<T>> супротив IAsyncEnumerable<T>.
Пока что настораживает https://github.com/JoshClose/CsvHelper/issues/1560.
Хотя статья в MSDN описывает подкапотность async yield return довольно позитивненько.
Вроде бы приложен максимум усилий к тому, чтобы код не тормозил.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sharov, Вы писали: S>Никогда не задумывался, а json может работать потоково? Т.е. когда сериализумемая структура имеется не полностью?
Внезапно обнаружил вот такой вот сниппет:
private async IAsync Enumerable<Data> Generate(int maxItems)
{
var random = new Random();
for (int i = 0; i < maxItems; i++)
{
yield return new Data
{
Id = i,
Value = random.Next().ToString()
};
}
}
public async Task SerializeStream()
{
using var stream = Console.OpenStandardOutput();
var data = new { Data = Generate(30) };
await JsonSerializer.SerializeAsync(stream, data);
}
То есть да — внезапно, System.Text.Json из коробки cможет работать потоково, начиная с .Net 6. В том числе и асинхронно сериализовывать данные, готовые не полностью. Безо всяких приседаний вроде тех, что я привёл в предыдущем ответе.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>? Хотя, в целом даже и первый вариант выглядит не слишком отвратительно.
я бы предпочел этакий SelectMany, который берет элемент их асинхронного источника, клеит его с проекцией элемента в синхронную коллекцию, и возвращает, по всей видимости, IAsyncEnumerable<TResult>.
Здравствуйте, samius, Вы писали:
S>Здравствуйте, Sinclair, Вы писали:
S>>Да, верно. А не завернуть ли нам чтение из такого источника в хелпер? S>>Типа вместо S>>
S>>await foreach(var page in db.GetPages<Product>(...))
S>> foreach(var p in page)
S>> this.Writer.Write(p);
S>>
S>>? Хотя, в целом даже и первый вариант выглядит не слишком отвратительно. S>я бы предпочел этакий SelectMany, который берет элемент их асинхронного источника, клеит его с проекцией элемента в синхронную коллекцию, и возвращает, по всей видимости, IAsyncEnumerable<TResult>.
хм. Типа
await foreach(var p in from page in db.GetPages<Product>()
from p in page select p)
await this.Writer.Write(p);
?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.