Ленивый поток для C#/.NET

Кто-нибудь знает о реализации ленивого потока в .net? IOW, я хочу создать такой метод:

public Stream MyMethod() {
    return new LazyStream(...whatever parameters..., delegate() {
        ... some callback code.
    });
}

и когда мой другой код вызывает MyMethod() для возврата и извлечения потока, он фактически не будет выполнять никакой работы, пока кто-то действительно не попытается прочитать из потока. Обычным способом было бы заставить MyMethod принимать параметр потока в качестве параметра, но в моем случае это не сработает (я хочу передать возвращенный поток в MVC FileStreamResult).

Чтобы дополнительно объяснить, что я ищу, это создать многоуровневую серию преобразований, поэтому

Набор результатов базы данных = (преобразован в) => поток байтов = (связан с) => GZipStream = (передан в) => конструктор FileStreamResult.

Результирующий набор может быть огромным (ГБ), поэтому я не хочу кэшировать результат в MemoryStream, который я могу передать конструктору GZipStream. Скорее, я хочу получить из набора результатов по мере того, как GZipStream запрашивает данные.


person erikkallen    schedule 10.11.2009    source источник
comment
Реализация IEnumerable‹byte› или чего-то еще не работает для вас?   -  person Jason Kleban    schedule 11.11.2009
comment
Теоретически да, мог бы, если бы существовал поток, конструктор которого принимал IEnumerable‹byte›. Хотя это кажется ужасно неэффективным (но преждевременная оптимизация — корень всех зол).   -  person erikkallen    schedule 11.11.2009


Ответы (3)


Этот ответ (https://stackoverflow.com/a/22048857/1037948) ссылается на эта статья о том, как напишите свой собственный потоковой класс.

Чтобы процитировать ответ:

Производитель записывает данные в поток, а потребитель читает. Посередине есть буфер, чтобы производитель мог немного опережать запись. Вы можете определить размер буфера.

Цитирую первоисточник:

Вы можете думать о ProducerConsumerStream как об очереди с интерфейсом Stream. Внутри он реализован как кольцевой буфер. Два индекса отслеживают точки вставки и удаления в буфере. Байты записываются в индекс Head и удаляются из индекса Tail.

Если Head переходит в Tail, то буфер заполнен, и производителю приходится ждать, пока будут прочитаны некоторые байты, прежде чем он сможет продолжить запись. Точно так же, если Tail догоняет Head, потребитель должен дождаться записи байтов, прежде чем он сможет продолжить.

Далее в статье описываются некоторые странные случаи, когда указатели зацикливаются, с полными примерами кода.

person drzaus    schedule 28.05.2015
comment
Эта ссылка мертва. - person Puppy; 23.09.2016
comment
Спасибо, @Puppy, попробуйте Wayback Machine в следующий раз, когда обнаружится неработающая ссылка: https://web.archive.org/web/20151210235510/http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=852 - person drzaus; 27.09.2016

Большинство реализаций потоков по своей природе являются ленивыми потоками. Как правило, любой поток не будет считывать информацию из своего источника, пока она не будет запрошена пользователем потока (кроме некоторого дополнительного «избыточного чтения», позволяющего выполнять буферизацию, что значительно ускоряет использование потока).

Было бы довольно легко создать реализацию Stream, которая не читала бы до тех пор, пока это не потребуется, переопределив Чтение, чтобы открыть базовый ресурс, а затем прочитать его при использовании, если вам нужна полностью ленивая реализация потока. Просто переопределите Read, CanRead, CanWrite и CanSeek.

person Reed Copsey    schedule 10.11.2009

В вашем классе Stream вы должны реализовать несколько методов System.IO.Stream, включая метод Read.

Что вы делаете в этом методе, зависит от вас. Если вы решите вызвать делегата — это тоже зависит от вас, и, конечно же, вы можете передать этот делегат как один из параметров вашего конструктора. По крайней мере, я бы так поступил.

К сожалению, потребуется больше, чем реализация метода чтения, и ваш делегат не будет охватывать другие необходимые методы.

person mfeingold    schedule 10.11.2009
comment
Да, я знаю, я просто надеюсь, что кто-то другой написал этот класс. - person erikkallen; 11.11.2009