【问题标题】:Create an observable wrapper for a non thread safe class为非线程安全类创建一个可观察的包装器
【发布时间】:2011-08-16 10:42:15
【问题描述】:

我有课,

public class Test
{
  public int Calc();
}

这要求对 Calc 的所有调用都在与创建 Test 的线程相同的线程上执行。我需要创建一次Test(操作成本高)并多次调用Calc。

我想要一个可以让我异步调用 Calc 的包装器:

public class TestWrapper
{
  private Test _test;
  public IObservable<int> Calc();
}

一种方法是创建一个 BackgroundWorker 或一个 Thread 并使用它来保证 Test 上的所有操作都在同一个线程上。为简单起见,我们可以假设所有对 Calc() 的调用都将按顺序执行,因此无需担心排队。

有没有更优雅的 RX 方式来做到这一点?

【问题讨论】:

    标签: c# system.reactive


    【解决方案1】:

    如果在创建TestWrapper 时可以创建Test,那么这个类似乎满足您的要求:

    public class TestWrapper
    {
        public TestWrapper(Func<Test> factory)
        {
            _scheduler = new EventLoopScheduler();
            _test = Observable.Start(factory, _scheduler).First();
        }
    
        private readonly EventLoopScheduler _scheduler;
        private readonly Test _test;
    
        public IObservable<int> Calc()
        {
            return Observable.Start(() => _test.Calc(), _scheduler);
        }
    }
    

    它是这样使用的:

    var testWrapper = new TestWrapper(() => new Test());
    testWrapper.Calc().Subscribe(x => { });
    

    我已经对其进行了测试,它在执行Calc 的同一线程上创建了Test。另一方面,订阅是在与 testWrapper 本身在同一线程上创建的(即调用线程)上处理的。

    【讨论】:

      【解决方案2】:

      因此,从 cmets 并重新阅读您的问题,我了解到您想在恒定线程上重复调用 Calc() 并将返回结果作为 IObservable&lt;Int&gt;() 提供?

      在这种情况下,我会使用 Observable.Create 来包装 Test 类,并使用 EventLoopScheduler 来确保对 Calc 的调用在单个线程上。

      public class TestWrapper
      {
        private Test _test;
        public IObservable<int> Calc()
        {
          return Observable.Create(obsvr =>
          {
              var fixedThreadsched = new EventLoopScheduler();
              var disp = new BooleanDisposable();
              while (!disp.IsDisposed)
              {
                  fixedThreadsched.Schedule(() => obsvr.OnNext(_test.Calc()));
              }
      
              return disp;
          });
        }
      }
      

      【讨论】:

      • 谢谢,EventLoopScheduler 是将调用编组到同一线程的关键。尽管如此,这个答案并没有解释如何从将在 UI 线程上执行的 TestWrapper.Calc 切换到 test.Calc ...
      • @Sergey - 根据您的 cmets 更新
      • 这更接近了...缺少的部分是您没有创建 _test (应该在 EventLoopScheduler 上完成)。嗯......很难决定 - 你是第一个使用 EventLoopScheduler 但@enigmativity 提供了正确答案。谢谢你们两个摇滚!
      • 很公平,但上面应该清楚地说明如何做到这一点
      【解决方案3】:

      在创建Test 的实例时使用ThreadLocal&lt;T&gt; 类:

      var MyTEST = new ThreadLocal<Test>();
      

      那么您可以使用MyTEST.Value.Calc () 拨打任何电话...

      另一种选择是在包装类的 Test 成员上使用 put [ThreadStatic]... 见http://msdn.microsoft.com/en-us/library/system.threadstaticattribute.aspx

      根据您是否需要多个Test 实例,您可以将其设为Singleton

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多