将线程旋转以拉入Rx

时间:2013-08-20 00:29:52

标签: c# system.reactive

我试图使用Chunkify方法来“捕获”所有“待定”项目。 但我发现了一个问题,消耗了一个线程的所有资源,有谁知道为什么会发生这种情况,我该如何防止这种情况?

事实上,我的目标是为我的活动创建一个“垃圾邮件过滤器”,仅选择最后5个值,并忽略连续两次以上的重复。

问题发生的一个例子:

注意!以下代码是愚蠢而毫无意义的。它只是为了演示问题,并指出该事件可以被称为多个线程 (请运行上面的代码并观察输出窗口,这是问题所在。)

    [TestMethod]
    public void ThreadSpinning()
    {

     var subs = Observable.FromEventPattern(add => this.Raise += add, rem => this.Raise -= rem)
                           .Select((item, countRaise) => countRaise)
                           .Chunkify()
                           .ToObservable(Scheduler.Default)
                           .Select((countRaise, countChunkify) => new { raiseItems = countRaise, countChunkify })
                           .Do(obj => Trace.Write("Chunkify = " + obj.countChunkify + " | "))
                           .Select(a => a.raiseItems)
                           .Where(a => a.Any())
                           .Do(obj =>
                           {
                               Trace.WriteLine("[ Start do something.. Raise = " + Dump(obj) + " ] " +
                                               Environment.NewLine + Environment.NewLine);

                               Thread.Sleep(700);
                           }).Subscribe();

        Thread.Sleep(2000);

        var handle = new ManualResetEventSlim(false);
        ThreadPool.QueueUserWorkItem(r =>
            {
                Thread.Sleep(500);

                Task.Factory.StartNew(() =>
                {
                    OnRaise();
                    OnRaise();

                }).Wait();

                OnRaise();
                Thread.Sleep(500);
                OnRaise();
                Task.Factory.StartNew(OnRaise).Wait();
                Thread.Sleep(1500);
                OnRaise();
                OnRaise();

                Thread.Sleep(500);

                OnRaise();

                Thread.Sleep(250);

                OnRaise();
                Task.Factory.StartNew(OnRaise).Wait();
                Thread.Sleep(500);
                Task.Factory.StartNew(OnRaise).Wait();
                Task.Factory.StartNew(OnRaise).Wait();
                Thread.Sleep(2000);

                handle.Set();
            });

        handle.Wait();
        Thread.Sleep(3000); 
        subs.Dispose();

        Thread.Sleep(1000); 
    }

    private event EventHandler Raise;

    protected virtual void OnRaise()
    {
        EventHandler handler = Raise;
        if (handler != null) 
            handler(this, EventArgs.Empty);
    }

    public static string Dump<T>(IEnumerable<T> source)
    {
        return source.Select(a => a.ToString()).Aggregate((a, b) => a + ", " + b);
    }

1 个答案:

答案 0 :(得分:1)

我不确定您要做什么,但您的代码存在一些问题:

  • 您正在使用ChunkifyIObservable转换为IEnumerable,但之后又将其转换为IObservable,这有点奇怪。

  • 陈述

              .Select((item, count) => new { item, count })
              .Do(obj => Trace.Write(obj.count + " | "))
              .Select(a => a.item)
              .Where(a => a.Any())
              .Do(obj => Trace.WriteLine("Do something.. " + obj.Dump()))
    

    很多代码似乎只是为了调试而进行转换。您可以在一个Do调用中的一个语句lambda中编写所有调试代码。

  • 您不应该创建新的Random个对象,而是重用一个并在其上调用Next()http://msdn.microsoft.com/en-us/library/h343ddh9.aspx

  • 您过度使用Thread.Sleep,并且在可观察的序列中执行此操作会产生代码异味。尝试将代码转换为使用各种时间运算符,例如ThrottleDelay。您可能还想使用Observable.Generate创建序列。

  • Chunkify可能实际上与您无关 - 您是否考虑过Buffer运营商?这里有一个很好的时间运算符列表:http://introtorx.com/Content/v1.0.10621.0/13_TimeShiftedSequences.html#TimeShiftedSequences

  • 要测试代码,您不需要实际引发事件处理程序,只需通过生成可观察序列并订阅它来测试您的订阅代码。例如,如果您有一个方法SubscribeToMyEvent(IObservable<T>),那么您可以通过传递使用FromEventPattern创建的可观察量或使用IntervalGenerate创建的方法来设置它。

你的情景究竟是什么?什么是触发事件?你究竟想要改变你的事件流?绘制大理石图(例如http://channel9.msdn.com/blogs/j.van.gogh/reactive-extensions-api-in-depth-marble-diagrams-select--where)以便考虑您的算法会很有帮助。