C# 生成IObservable的首选方法<;字符串>;溪流
作为我们应用程序的一部分(目前已投入生产大约4个月),我们有一个来自外部设备的数据流,我们将其转换为IObservable 到目前为止,我们一直在使用下面的代码来生成它,并且它运行得非常好C# 生成IObservable的首选方法<;字符串>;溪流,c#,system.reactive,reactive-programming,C#,System.reactive,Reactive Programming,作为我们应用程序的一部分(目前已投入生产大约4个月),我们有一个来自外部设备的数据流,我们将其转换为IObservable 到目前为止,我们一直在使用下面的代码来生成它,并且它运行得非常好 IObservable<string> ObserveStringStream(Stream inputStream) { var streamReader = new StreamReader(inputStream); return Observable
IObservable<string> ObserveStringStream(Stream inputStream)
{
var streamReader = new StreamReader(inputStream);
return Observable
.Create<string>(observer => Scheduler.ThreadPool
.Schedule(() => ReadLoop(streamReader, observer)));
}
private void ReadLoop(StreamReader reader, IObserver<string> observer)
{
while (true)
{
try
{
var line = reader.ReadLine();
if (line != null)
{
observer.OnNext(line);
}
else
{
observer.OnCompleted();
break;
}
}
catch (Exception ex)
{
observer.OnError(ex);
break;
}
}
}
它似乎工作得很好,而且更干净,但我想知道一种方法是否优于另一种方法,或者是否有更好的方法。我认为你有一个好主意(将
流
转换为可枚举
然后可观察
)。但是,IEnumerable代码可以更干净:
IEnumerable<string> ReadLines(Stream stream)
{
using (StreamReader reader = new StreamReader(stream))
{
while (!reader.EndOfStream)
yield return reader.ReadLine();
}
}
IEnumerable可读行(流)
{
使用(StreamReader=新StreamReader(stream))
{
而(!reader.EndOfStream)
产生返回reader.ReadLine();
}
}
然后对于可观察的IObservable:
IObservable<string> ObserveLines(Stream inputStream)
{
return ReadLines(inputStream).ToObservable(Scheduler.ThreadPool);
}
IObservable observeline(流输入流)
{
返回ReadLines(inputStream).ToObservable(Scheduler.ThreadPool);
}
这是更短、更可读的,并且正确地处理了流。它也很懒
ToObservable
扩展负责捕获OnNext
事件(新行)以及OnCompleted
事件(可枚举的结尾)和OnError
我手头没有代码,但这里介绍了如何执行异步预异步CTP
[略读读者注意:如果您不需要进行太多扩展,则无需费心]
创建一个本身可观察的AsyncTextReader实现。ctor接收一个流,并对该流执行起始(256bytes),将自身作为延续传递,然后返回
输入continuation后,调用EndRead,并将返回的字节添加到类的一个小缓冲区中。重复此操作,直到缓冲区包含一个或多个行尾序列(根据TextWriter)。发生这种情况时,通过Observable接口将缓冲区的这些位作为字符串发送出去,然后重复
完成后,发出完成信号等。。。(并处理该流)。如果在continuation中从EndReadByte引发异常,请捕获它并将其传递给OneError接口
调用代码如下所示:
IObservable=新的AsyncTextReader(流)
这个比例很好。只需要确保在处理缓冲区时不要做太愚蠢的事情
伪代码:
public ctor(Stream stream){
this._stream = stream;
BeginRead();
return;
}
private void BeginRead(){
// kick of async read and return (synchronously)
this._stream.BeginRead(_buffer,0,256,EndRead,this);
}
private void EndRead(IAsyncResult result){
try{
// bytesRead will be *up to* 256
var bytesRead = this._stream.EndRead(result);
if(bytesRead < 1){
OnCompleted();
return;
}
// do work with _buffer, _listOfBuffers
// to get lines out etc...
OnNext(aLineIFound); // times n
BeginRead(); // go round again
}catch(Exception err){
OnException(err);
}
}
public-ctor(流){
这个。_stream=stream;
开始();
返回;
}
私有的无效开始(){
//异步读取和返回的触发(同步)
this._stream.BeginRead(_buffer,0256,EndRead,this);
}
私有void EndRead(IAsyncResult结果){
试一试{
//字节读取将为*至*256
var bytesRead=this.\u stream.EndRead(结果);
如果(字节读取<1){
未完成();
返回;
}
//请使用_buffer、_buffers列表
//把线路排出去等等。。。
OnNext(aLineIFound);//次n
beginhead();//再绕一圈
}捕获(异常错误){
一个例外(err);
}
}
好的,这是APM,只有母亲才会喜欢。我热切地等待着另一种选择
ps:读者是否应该关闭流是一个有趣的问题。我说不,因为它没有创建它。使用async/await支持,以下最有可能是您的最佳选择:
IObservable<string> ObserveStringStream(Stream inputStream)
{
return Observable.Using(() => new StreamReader(inputStream),
sr => Observable.Create<string>(async (obs, ct) =>
{
while (true)
{
ct.ThrowIfCancellationRequested();
var line = await sr.ReadLineAsync().ConfigureAwait(false);
if (line == null)
break;
obs.OnNext(line);
}
obs.OnCompleted();
}));
}
IObservable ObserveStringStream(流输入流)
{
返回可观察的。使用(()=>新的StreamReader(inputStream),
sr=>Observable.Create(异步(obs,ct)=>
{
while(true)
{
ct.ThrowIfCancellationRequested();
var line=await sr.ReadLineAsync().ConfigureAwait(false);
如果(行==null)
打破
obs.OnNext(行);
}
obs.OnCompleted();
}));
}
Pro:yield return
支持延迟/延迟加载集合。Con:当抛出异常时,它不会调用一个异常,它只是冒泡,我想这取决于您是否介意烧掉一个线程来执行读取循环,这取决于您需要支持的设备数量。我写了一个AsyncTextReader,它本身可以观察到做一些类似的事情,但规模很大。当然这些天你可以等待一些事情…@MatthewFinlay事实上,一个例外似乎是有效的,如果我订阅并包括OnNext、OnError和OnCompleted的操作,我会得到所有3个被称为预期的Hanks Lee。我确实读过那篇文章。它是可观察的吗?使用它可以支持取消?如果是这样的话,这样的东西不能工作(基于我的ReadLoop方法)?可观察。使用(()=>newstreamreader(inputStream),sr=>ReadLoop(sr).ToObservable(Scheduler.ThreadPool));很好,很干净。明天我得试一试。我唯一担心的是,我可能会得到一个尾随null作为可观察项中的最后一项,但这很容易过滤掉。其中(line=>line!=null)
IObservable<string> ObserveStringStream(Stream inputStream)
{
return Observable.Using(() => new StreamReader(inputStream),
sr => Observable.Create<string>(async (obs, ct) =>
{
while (true)
{
ct.ThrowIfCancellationRequested();
var line = await sr.ReadLineAsync().ConfigureAwait(false);
if (line == null)
break;
obs.OnNext(line);
}
obs.OnCompleted();
}));
}