我有一个Observable流,每次文件监视程序检测到发生更改时,该流就会被打勾。然后,此勾号将导致嵌套的Observable开始,以重复读取打开的文件流,直到读取所有新更新,然后将它们展平为最终输出流。
我的问题是,如果文件发生更改,则启动嵌套的Observable,如果此嵌套的Observable仍在读取文件中的行,并且在文件发生第二次更改时尚未完成,则文件观察器可观察到会导致SECOND嵌套可观察到的事件开始,因此您有两个嵌套可观察到的对象都试图从同一流中读取,这会导致InvalidOperationException-流正在被另一个进程使用
如何更改此Observable,使其仅在上一个Observable完成时才允许父Observable创建嵌套的Observable?就是说,像手动重置事件那样控制可观察的父对象,它仅允许它在先前的嵌套操作完成并停止使用流后才能继续?
我的代码
var fileSystemWatcherChanges = Observable<Unit>()
/// abbreviated for question, code here opens a file watcher to create this stream
var outputStream = fileSystemWatcherChanges
.StartWith(Unit.Default)
.Select(x =>
Observable
.Defer(() => Observable.FromAsync(sr.ReadLineAsync))
.Repeat()
.TakeUntil(w => w == null))
.Merge()
.Where(w => w != null))
使用解决方案更新:
对于那些有兴趣解决此问题的人,我已经做了一些基本的锁定,看来已经解决了这个问题。如果我们当前仍在处理内部可观察的内容,它将忽略滴答声,在这种情况下,我相信这是令人满意的,因为更新滴答声仅告诉我们有更多行需要读取,而当前正在执行的ReadLine observable应该选择这些新行如果他们在那里。在我们积极处理文件流时,我们不在乎任何文件更新触发器。
var readingFile = 0;
var outputStream = fileSystemWatcherChanges
.StartWith(Unit.Default)
.Select(delegate(Unit x)
{
// Deny a second file update from starting to read the stream if we are already reading it
if (0 == Interlocked.Exchange(ref readingFile, 1))
{
return Observable
.Defer(() => Observable.FromAsync(sr.ReadLineAsync))
.Repeat()
.TakeUntil(w => w == null)
.Finally(() => Interlocked.Exchange(ref readingFile, 0));
}
return Observable.Empty<string>();
})
.Merge()
.Where(w => w != null))
答案 0 :(得分:0)
您应该使用Merge
而不是Concat
,它会订阅下一个可观察到的对象,直到上一个观察完成为止:
public static IObservable<string> ReadAsObservable<TNotification>(this TextReader reader, IObservable<TNotification> notification)
{
return Observable.Using(() => reader,
r =>
{
var readLine = Observable.FromAsync(r.ReadLineAsync);
return notification.Select(_ => readLine.Repeat().TakeWhile(x => x != null))
.Concat();
});
}