行为真的很奇怪,它看起来像框架本身的一个大错误,
我有一个FileSystemWatcher来检测文件夹中的新文件,每次检测到新文件时,都会在发送Rx .OnNext通知之前解析并删除该文件:
private Subject<MyObject> objectNotification = new Subject<MyObject>();
private FileSystemWatcher watcher;
private void MyClassConstructor(string pathToWatch)
{
watcher= new FileSystemWatcher();
watcher.Filter = scraper.Ext;
watcher.Created += new FileSystemEventHandler(parseMethod);
watcher.Path = pathToWatch;
watcher.EnableRaisingEvents = true;
}
private void parseMethod(object sender, FileSystemEventArgs e)
{
MyObject parsedFile = new MyObject(e.FullPath);
File.Delete(e.FullPath);
var syncedSubject = Subject.Synchronize(objectNotification);
syncedSubject.OnNext(parsedFile);
}
另一方面,在主应用程序的GUI代码中的某处有接收代码:
private IDisposable myObjectSubscription;
.
.
.
private void initSubscription()
{
this.myObjectSubscription = sendingClass.Subscribe(parsedObject =>
{
this.AddObject(parsedObject);
});
}
private void addObject(MyObject parsedObject)
{
//Sometimes the same object is being received many times, but has been sent only once!
//BUG!
}
理想情况下,我应该在观察者中收到发送者类发送的每个值的通知,不幸的是我得到更多,更多!
答案 0 :(得分:2)
可观察同步是这个问题的核心问题。
存在Subject或Observable同步方法以防止进行并发OnXXX
调用。
因为同步在没有必要时引入了开销(这通常就足够了),并且由于下面描述的替代方法,Rx API的用户需要决定何时以及如何同步。
在您的情况下,每次引发事件并调用事件处理程序时,parseMethod
都会为该事件创建一个新的同步主题。这不是您想要的,也不会阻止并发OnNext()
次呼叫。因此,由于观察者OnNext()
处理程序中的并发调用,您会看到竞争条件错误。
不是在parseMethod
中创建同步主题,而是在构造函数中执行或者在订阅上进行同步,它应该可以工作。
e.g。 :
要么这样做:
private ISubject<MyObject,MyObject> objectNotification =
Subject.Synchronized(new Subject<MyObject>());
...
private void parseMethod(object sender, FileSystemEventArgs e)
{
MyObject parsedFile = new MyObject(e.FullPath);
File.Delete(e.FullPath);
objectNotification.OnNext(parsedFile);
}
或者这样做:
private void initSubscription()
{
this.myObjectSubscription = sendingClass.Synchronize().Subscribe(parsedObject =>
{
this.AddObject(parsedObject);
});
}
请注意,如果有多个订阅者,这些替代方案会有不同的行为!
在第一种情况下,您确保在所有观察者中至少有一个OnNext()
在飞行中。第一个事件发送到第一个订户,然后发送到第二个订户...直到所有订户都收到该事件,然后发送第二个事件等。
在第二种情况下,您会介绍一些(通常是安全的)并发性 - 现在您确保在特定事件中 中最多只有一个OnNext()
所有观察员。换句话说,可以对 不同观察者 中的 不同事件 进行并发OnNext()
次调用,但只有 一个 OnNext()
对特定事件的调用才会在任何时候进行,并且不会对同一个观察者进行并发调用。
您更喜欢哪个,后者允许观察者并行运行,但仍会阻止您看到的问题;哪种方法更好取决于上面未提供的实施细节。