C# 如何使用1000个观察者高效地运行Observable.Where()?

C# 如何使用1000个观察者高效地运行Observable.Where()?,c#,performance,system.reactive,C#,Performance,System.reactive,我是Rx的新手,我绝对喜欢它。我发现代码的现有部分可以通过使用它大大简化。我遇到了一个性能问题,如果有一位大师能帮助我,我将不胜感激 以前,我有一个手动实现的observer类,它接受订阅和一个键过滤器。当事件进入类时,它将使用提供的键查找哪些观察器需要回调。这是一个非常简化的代码版本: class OldClass { private Dictionary<string, List<Action<UsefulInfo>> _callbacks =

我是Rx的新手,我绝对喜欢它。我发现代码的现有部分可以通过使用它大大简化。我遇到了一个性能问题,如果有一位大师能帮助我,我将不胜感激

以前,我有一个手动实现的observer类,它接受订阅和一个键过滤器。当事件进入类时,它将使用提供的键查找哪些观察器需要回调。这是一个非常简化的代码版本:

 class OldClass
 {
    private Dictionary<string, List<Action<UsefulInfo>> _callbacks = 
        new Dictionary<string, List<Action<UsefulInfo>>();

    void Subscribe(string key, Action<UsefulInfo> callback)
    {
        _callbacks[key].Add(callback);
    }

    // Some event happens that we want to notify subscribers about
    void EventHandler(object sender, SomeEventArgs e)
    {
        // Create object for callbacks
        UsefulInfo info = CreateUsefulInfo(e);

        string key = info.Key;

        // Look up callbacks for key
        _callbacks[key].ForEach(callback => callback(info));
    }
 }
class-OldClass
{

私有词典您可以通过在
Where'd
序列上使用共享观察者,然后在
IConnectableObservable
上使用来更智能地管理对源的订阅

在您的场景中,我想象您将这些“已发布”的观测值存储在字典中,并根据需要添加到它们中

以下是一个基本实现:

class NewClass 
{ 
    private Subject<UsefulInfo> _subject = new Subject<UsefulInfo>(); 
    private IDictionary<string, IObservable<UsefulInfo>> _keyedObservables; 

    public NewClass() 
    { 
        _keyedObservables = new Dictionary<string, IObservable<UsefulInfo>>();
    } 

    IDisposable Subscribe(string key, Action<UsefulInfo> callback) 
    { 
        // NOT threadsafe for concurrent subscriptions!
        if (!_keyedObservables.Contains(key))
        {
            var keyedAndPublished = _subject.Where(x => x.Key == key)
                .Publish()
                .RefCount();

            _keyedObservables.Add(key, keyedAndPublished);
        }

        return _keyedObservables[key].Subscribe(callback);
    } 

    // Some event happens that we want to notify subscribers about 
    void EventHandler(object sender, SomeEventArgs e) 
    { 
        UsefulInfo info = CreateUsefulInfo(e); 

        _observable.OnNext(info); 
    } 
} 
class新类
{ 
私人主语_Subject=新主语();
私有IDictionary _keyedObservable;
公共类()
{ 
_keyedObservables=新字典();
} 
IDisposable订阅(字符串键、操作回调)
{ 
//对于并发订阅,不是线程安全的!
if(!\u keyedObservables.Contains(key))
{
var keyedAndPublished=\u subject.Where(x=>x.Key==Key)
.Publish()
.RefCount();
_添加(键、键和已发布);
}
返回_keyedObservables[key]。订阅(回调);
} 
//发生了一些我们想通知订阅者的事件
void EventHandler(对象发送方,SomeEventArgs e)
{ 
UsefulInfo=CreateUsefulInfo(e);
_observable.OnNext(信息);
} 
} 

谢谢你花时间回答这个问题,Richard。我是Rx的新手,所以你介意稍微扩展一下吗?@JamesD-我添加了一个实现。这可能有助于进一步解释IConnectableObservable。你是个天才,这很有意义。非常感谢你花时间。我刚刚将代码粘贴到一个简单的测试项目中,然后运行它。它确实会为每个键共享观察者。问题是,大多数调用的观察者都有不同的键。因此,对于每个键,主题上的Where func仍然会调用一次,每个事件都会调用1000次。这有意义吗?@JamesD-考虑到有1000个唯一键,我认为Rx不能做你想做的事情在使用单个主题之后。我建议为每个键创建一个主题,并将其存储在字典中。
class NewClass 
{ 
    private Subject<UsefulInfo> _subject = new Subject<UsefulInfo>(); 
    private IDictionary<string, IObservable<UsefulInfo>> _keyedObservables; 

    public NewClass() 
    { 
        _keyedObservables = new Dictionary<string, IObservable<UsefulInfo>>();
    } 

    IDisposable Subscribe(string key, Action<UsefulInfo> callback) 
    { 
        // NOT threadsafe for concurrent subscriptions!
        if (!_keyedObservables.Contains(key))
        {
            var keyedAndPublished = _subject.Where(x => x.Key == key)
                .Publish()
                .RefCount();

            _keyedObservables.Add(key, keyedAndPublished);
        }

        return _keyedObservables[key].Subscribe(callback);
    } 

    // Some event happens that we want to notify subscribers about 
    void EventHandler(object sender, SomeEventArgs e) 
    { 
        UsefulInfo info = CreateUsefulInfo(e); 

        _observable.OnNext(info); 
    } 
}