Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 4.0 Rx TaskPoolScheduler与EventLoopScheduler,内存使用情况_C# 4.0_System.reactive_Reactive Programming - Fatal编程技术网

C# 4.0 Rx TaskPoolScheduler与EventLoopScheduler,内存使用情况

C# 4.0 Rx TaskPoolScheduler与EventLoopScheduler,内存使用情况,c#-4.0,system.reactive,reactive-programming,C# 4.0,System.reactive,Reactive Programming,我正在尝试对大量独立的数据源进行POC。一种经典的观察者风格的应用程序。数据源的数量可能从几百到几千不等,观察者的数量可能从2到20000不等。下面是一个简单的数据馈送可观察模型的快速示例: public class FeedMockUp { private readonly IScheduler observerScheduler; private readonly Random rnd = new Random((int)DateTime.No

我正在尝试对大量独立的数据源进行POC。一种经典的观察者风格的应用程序。数据源的数量可能从几百到几千不等,观察者的数量可能从2到20000不等。下面是一个简单的数据馈送可观察模型的快速示例:

    public class FeedMockUp
    {
        private readonly IScheduler observerScheduler;
        private readonly Random rnd = new Random((int)DateTime.Now.Ticks);

        private readonly Subject<double> sourceObservable;
        private readonly IObservable<double> testedObservable;

        public FeedMockUp(IScheduler observerScheduler)
        {
            this.observerScheduler = observerScheduler;
            sourceObservable = new Subject<double>();

            testedObservable =
                Observable.Create<double>(x =>
                {
                    var underlyingSourceDisposable =
                        sourceObservable
                            .Subscribe(_ => x.OnNext(rnd.NextDouble()));
                    return underlyingSourceDisposable;
                });
        }

        public IDisposable SubscribeToUnderlyingFeed(int numberOfSubscribers)
        {
            int counter = 0;
            var disposable = new CompositeDisposable();

            for (int i = 0; i < numberOfSubscribers; i++)
            {
                disposable.Add(testedObservable
                    .ObserveOn(observerScheduler)
                    .Subscribe(_ => Interlocked.Increment(ref counter)));
            }

            return disposable;
        }

        public void PushNewFeed()
        {
            sourceObservable.OnNext(rnd.NextDouble());
        }
    }    

ObserveOn
TaskPoolScheduler
一起使用,实质上是为每个观察者创建一个任务

默认的
TaskScheduler
结束

每个线程为其堆栈保留大约1MB的内存

因此,使用
TaskPoolScheduler
的500个观察者将保留至少500MB的空间。你可以看到这是怎么回事

另一方面,
EventLoopScheduler
在单个线程上运行。因此,将
ObserveOn
与此调度器一起使用,只需向调度器的工作队列添加一个条目即可。这个条目比一个线程的1MB开销小得多

因此,在这种情况下,
EventLoopScheduler
的内存效率要高得多,但它也会连续通知观察者,如果有很多观察者,并且源以高频率生成,那么您将开始积累未发送事件的缓冲区


TaskPoolScheduler
的内存效率较低,但会同时通知观察者,因此可能会通过利用计算机上的所有内核来处理比
EventLoopScheduler
频率更高的事件。

您可能希望使用
TaskPoolScheduler.Default.DisableOptimizations(typeof(IsSchedulerLongRunning))
。如果您不介意失去并行性,EventLoopScheduler是一个不错的选择


如果您仍然希望并行执行工作,但希望使用线程池线程,则最好使用此选项。

您还可以为每个核心创建一个
EventLoopScheduler
,并在入口点上实现负载平衡器;例如,循环调度程序选择。这可以包装在其自己的
IScheduler
implementat中ion,因此您只需要传递一个引用。当线程池开始增加时,看着内存呈指数级增长,这是非常有趣的。修复了该拼写错误。顺便说一句,Dave。此外,我在过去成功地使用了您建议的方法。
    private static void Main(string[] args)
    {
        const int displayItemCount = 100;
        const int callbackCount = 500;

        //var rtScheduler = new EventLoopScheduler(); 
        var rtScheduler = TaskPoolScheduler.Default;
        var rtFeeds = new List<FeedMockUp>();
        for (int i = 0; i < displayItemCount; i++)
        {
            var mockFeed = new FeedMockUp(rtScheduler);
            mockFeed.SubscribeToUnderlyingFeed(callbackCount);
            rtFeeds.Add(mockFeed);
        }
        foreach (var rtFeedMockUp in rtFeeds)
        {
            rtFeedMockUp.PushNewFeed();
        }
        Console.WriteLine("Memory used for feed {0} mockups with {1} observers / callbacks. Memory {2} Mb",
            displayItemCount, callbackCount, Environment.WorkingSet / (1024 * 1024));
Console.ReadKey();

}