Ленивый поток для C # / .NET - PullRequest
4 голосов
/ 11 ноября 2009

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

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

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

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

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

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

Ответы [ 3 ]

5 голосов
/ 11 ноября 2009

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

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

0 голосов
/ 28 мая 2015

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

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

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

Цитировать первоисточник:

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

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

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

0 голосов
/ 11 ноября 2009

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

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

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

...