Ich habe den nächsten Monade Transformator:Faule Ausgabe von monadischen Aktion
newtype Pdf' m a = Pdf' {
unPdf' :: StateT St (Iteratee ByteString m) a
}
type Pdf m = ErrorT String (Pdf' m)
Grundsätzlich nutzt zugrunde liegende Iteratee
, der liest und verarbeitet PDF-Dokument (erfordert Random-Access-Quelle, so dass es das Dokument nicht hält in Speicher die ganze Zeit).
Ich muss eine Funktion implementieren, die PDF-Dokument speichern wird, und ich möchte, dass es faul ist, sollte es möglich sein, Dokument in konstantem Speicher zu speichern.
ich faul ByteString
produzieren kann:
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as BS
save :: Monad m => Pdf m ByteString
save = do
-- actually it is a loop
str1 <- serializeTheFirstObject
storeOffsetForTheFirstObject (BS.length str1)
str2 <- serializeTheSecondObject
storeOffsetForTheSecondObject (BS.length str2)
...
strn <- serializeTheNthObject
storeOffsetForTheNthObject (BS.length strn)
table <- dumpRefTable
return mconcat [str1, str2, ..., strn] `mappend` table
Aber tatsächliche Leistung bei früheren Ausgabe verlassen können. (Details:.. PDF-Dokument so „Referenztabelle“ mit absoluter Offset in Bytes jedes Objekt innerhalb des Dokuments genannt enthält Es hängt definitiv von der Länge des ByteString
pdf Objekts serialisiert)
Wie diese save
Funktion, um sicherzustellen, wird nicht erzwinge ganz ByteString
, bevor es zum Anrufer zurückbringt?
Ist es besser, Callback als Argument zu nehmen und es jedes Mal aufzurufen, wenn ich etwas ausgeben möchte?
import Data.ByteString (ByteString)
save :: Monad m => (ByteString -> Pdf m()) -> Pdf m()
Gibt es eine bessere Lösung?
Ich habe gerade eine "Implementierung" für die 'save' Funktion hinzugefügt, um das Problem zu verdeutlichen. Ja, es sollte ein 1-Pass-Algorithmus sein, aber das ist kein Problem. Das Problem selbst: Wenn ich 'mconcat' anrufe, um den endgültigen faulen' ByteString' zu erzeugen, habe ich es bereits im Speicher. Unter der Annahme einer sehr großen PDF-Datei habe ich nicht genug Speicher dafür. Ich möchte nur Offsets speichern, nicht den ByteString selbst. Der Callback-Ansatz scheint das Problem zu lösen, aber ich denke, es sollte eine bessere Lösung geben. – Yuras
Seltsam, aber ich habe keine Benachrichtigung über deine Bearbeitung am 6. Juni erhalten. Wie kann 'blaze-builder' mir helfen? 'Bulder' ist definitiv schneller als' ByteString', wenn Sie 'mappend' wollen, aber das Problem ist die Speichernutzung, nicht die Leistung. 'str1',' str2' usw. befinden sich bereits im Speicher (erzwungen von BS.length) vor 'mconcat'. – Yuras