Chunked Parsing mit FParsec
Frage
Ist es möglich, Eingaben in Chunks wie von einem Socket an einen FParsec-Parser zu senden? Wenn nicht, ist es möglich, das aktuelle Ergebnis und den nicht analysierten Teil eines Eingabestreams abzurufen, damit ich dies erreichen kann? Ich versuche, die vom SocketAsyncEventArgs
eingehenden Eingabestücke auszuführen, ohne ganze Nachrichten zu puffern.
Update
Der Grund für die Feststellung der Verwendung von SocketAsyncEventArgs
war, dass das Senden von Daten an einen CharStream
zu einem asynchronen Zugriff auf den zugrunde liegenden Stream
führen kann. Insbesondere möchte ich einen kreisförmigen Puffer verwenden, um die vom Socket eingehenden Daten zu übertragen. Ich erinnere mich an die FParsec-Dokumentation, in der festgestellt wurde, dass auf den zugrunde liegenden Stream
nicht asynchron zugegriffen werden sollte, daher hatte ich geplant, die Chunked-Analyse manuell zu steuern.
Letzte Fragen:
- Kann ich einen Umlaufpuffer unter meinem
Stream
verwenden, der an denCharStream
übergeben wird? - Muss ich mich in diesem Szenario nicht darum kümmern, das Chunking manuell zu steuern?
Lösung
Die normale Version von FParsec (jedoch nicht die Low) -Trust-Version ) liest die Eingabe chunk-weise oder "block-weise", wie ich es in der Dokumentation zum CharStream
. Wenn Sie also einen CharStream
aus einem System.IO.Stream
erstellen und der Inhalt groß genug ist, um mehrere CharStream
-Blöcke zu umfassen, können Sie mit dem Parsen beginnen, bevor Sie die Eingabe vollständig abgerufen haben.
Beachten Sie jedoch, dass der CharStream
den Eingabestream in Blöcken einer festen (aber konfigurierbaren) Größe verbraucht, d. h. die Read
-Methode des System.IO.Stream
so oft aufruft, wie es zum Füllen eines vollständigen Blocks erforderlich ist. Wenn Sie die Eingabe schneller analysieren, als Sie neue Eingaben abrufen können, wird der CharStream
möglicherweise blockiert, obwohl bereits einige nicht analysierte Eingaben vorhanden sind, da noch nicht genügend Eingaben vorhanden sind, um einen vollständigen Block zu füllen.
Update
Die Antwort (en) auf Ihre letzten Fragen: 42
-
Wie Sie den
Stream
implementieren, aus dem Sie denCharStream
erstellen, liegt ganz bei Ihnen. Die Einschränkung, an die Sie sich erinnern und die den parallelen Zugriff ausschließt, gilt nur für dieCharStream
-Klasse, die nicht threadsicher ist. -
Das Implementieren des
Stream
als zirkulärer Puffer wird wahrscheinlich beschränkt die maximale Entfernung, über die Sie zurückverfolgen können. -
Die Blockgröße des
CharStream
s beeinflusst, wie weit Sie zurückverfolgen können, wenn derStream
die Suche nicht unterstützt. -
Der einfachste Weg, Eingaben asynchron zu analysieren, besteht darin, die Analyse in einer asynchronen Aufgabe (d. h. in einem Hintergrundthread) durchzuführen. In der Aufgabe können Sie den Socket einfach synchron lesen oder, wenn Sie der Pufferung durch das Betriebssystem nicht vertrauen, eine Stream-Klasse wie den
BlockingStream
verwenden, der in dem Artikel beschrieben ist, den Sie im zweiten Kommentar unten verlinkt haben. -
Wenn die Eingabe leicht in unabhängige Blöcke unterteilt werden kann (z. B. Zeilen für ein zeilenbasiertes Textformat), ist es möglicherweise effizienter, sie selbst aufzuteilen und dann den Eingabeabschnitt nach Block zu analysieren.