无功扩展计时器

时间:2013-03-21 16:04:08

标签: c# system.reactive

我有一个HashSet。 Occasionlay,新值将添加到此哈希集。我要做的是让计时器在添加后的一分钟内从集合中删除每个元素。

我还是rx的新手,但这似乎是使用它的理想场合。

我试过这样的事情:

AddItem(string item)
{
  _mySet.Add(item);
  var timer = Observable.Timer(TimeSpan.FromSeconds(60), _scheduler);
  timer
      .Take(1)
      .Do(item => RemoveItem(item))
      .Subscribe(_ => Console.WriteLine("Removed {0}", item));
}

似乎工作正常(通过单元测试)。

有人看到这种方法有什么问题吗?

4 个答案:

答案 0 :(得分:3)

  1. Do调用中的lambda看起来不正确 - Observable.Timer生成int值,但您的集合是HashSet<string> - 这不应该编译。我猜这只是一个错字。

  2. Do:一般来说,您的订阅应该在Subscribe中完成。 Do用于副作用(我不喜欢流中副作用的想法,所以我避免它,但它对调试很有用)。

  3. TakeObservable.Timer在终止前只生成一个值,因此不需要Take运算符

  4. 我会把你的功能写成:

    AddItem(string item)
    {
        _mySet.Add(item);
        Observable.Timer(TimeSpan.FromSeconds(60), _scheduler)
            .Subscribe(_ => RemoveItem(item));
    }
    

答案 1 :(得分:2)

您不需要创建序列来执行此操作。你已经是一个好公民并使用Scheduler明确,所以只需使用它!

你可以为你的代码提供这个

AddItem(string item)
{
  _mySet.Add(item);
  //Note this does return an IDisposable if you want to cancel the subscription.
  _scheduler.Schedule(
    TimeSpan.FromSeconds(60),
    ()=>
    { 
        RemoveItem(item);
        Console.WriteLine("Removed {0}", item);
    });
}

这基本上意味着在封面下进行的工作要少得多。考虑Observable.Timer方法的所有工作,当你只想要它做的时候,就是安排一个带有值的OnNext(你忽略了)。

我还假设即使对Rx一无所知的用户也能够读取此调度代码。即。 “在我添加此项目后,我将此删除操作计划为在60秒内运行。”

答案 2 :(得分:0)

如果您使用的是ReactiveUI,那么名为ReactiveCollection的类肯定会对您有所帮助,您可以像这样使用它:

theCollection.ItemsAdded
    .SelectMany(x => Observable.Timer(TimeSpan.FromSeconds(60), _scheduler).Select(_ => x))
    .Subscribe(x => theCollection.Remove(x));

答案 3 :(得分:-2)

对不起,不是故意选择你,而是:

始终禁止IDISPOSABLES !!!!!

(编辑:好的,不知道我今天早上放在咖啡里的是什么,但我回答的是一堆乱七八糟的废话;我会留下上面只是因为一般,你我想确保处置任何IDisposable,但是为了弥补随后的喋喋不休......)

<击> 对Subscribe的调用创建了一个你没有处理的订阅,所以对这个方法的多次调用只会排队越来越多的垃圾 - 现在在这个特定情况下,它不是自{{ {1}}只发射一次,但仍然......处理!

如果你真的想要使用这种方法(我认为更好的方法是让一些正在运行的线程/任务“倾向于”你的价值观,在它认为必要时删除),至少尝试类似于:

好的,忽略所有那些被淘汰的垃圾。 Timer的实施是这样的:

Observable.Timer

反过来调用这个:

public static IObservable<long> Timer(TimeSpan dueTime)
{
    return s_impl.Timer(dueTime);
}

调用...

public virtual IObservable<long> Timer(TimeSpan dueTime)
{
    return Timer_(dueTime, SchedulerDefaults.TimeBasedOperations);
}

这就是事情变得有趣的地方 - private static IObservable<long> Timer_(TimeSpan dueTime, IScheduler scheduler) { return new Timer(dueTime, null, scheduler); } 是一个Timer,其中的内容是:

Producer<long>

现在,private IDisposable InvokeStart(IScheduler self, object state) { this._pendingTickCount = 1; SingleAssignmentDisposable disposable = new SingleAssignmentDisposable(); this._periodic = disposable; disposable.Disposable = self.SchedulePeriodic<long>(1L, this._period, new Func<long, long>(this.Tock)); try { base._observer.OnNext(0L); } catch (Exception exception) { disposable.Dispose(); exception.Throw(); } if (Interlocked.Decrement(ref this._pendingTickCount) > 0) { SingleAssignmentDisposable disposable2 = new SingleAssignmentDisposable { Disposable = self.Schedule<long>(1L, new Action<long, Action<long>>(this.CatchUp)) }; return new CompositeDisposable(2) { disposable, disposable2 }; } return disposable; } ,即内部接收器设置为在计时器时间点触发,其中base._observer.OnNext就是:

Invoke

是的。它自动处理 - 并且不会有任何“挥之不去的订阅”。

嗯......乌鸦很好吃。 :|