RX.net

时间:2017-10-28 15:41:56

标签: c# c#-4.0 system.reactive reactive-programming reactive

我遇到了RX.net的背压问题我无法找到解决方案。我有一个可观察的实时日志消息流。

var logObservable = /* Observable stream of log messages */

我希望通过TCP接口公开,该接口在通过网络发送之前将来自logObservable的实时日志消息序列化。所以我做了以下几点:

foreach (var message in logObservable.ToEnumerable())
{
   // 1. Serialize message
   // 2. Send it over the wire. 
}

如果出现背压情况,.ToEnumerable()会出现问题,例如如果另一端的客户端暂停流。问题是.ToEnumerable()缓存导致大量内存使用的项目。我正在寻找像DropQueue这样的机制,它只缓冲最后10条消息,例如。

var observableStream = logObservable.DropQueue(10).ToEnumerable();

这是解决此问题的正确方法吗?您是否知道实施这样的机制以避免可能的背压问题?

1 个答案:

答案 0 :(得分:0)

我的DropQueue实施:

    public static IEnumerable<TSource> ToDropQueue<TSource>(
        this IObservable<TSource> source,
        int queueSize,
        Action backPressureNotification = null,
        CancellationToken token = default(CancellationToken))
    {
        var queue = new BlockingCollection<TSource>(new ConcurrentQueue<TSource>(), queueSize);
        var isBackPressureNotified = false;

        var subscription = source.Subscribe(
            item =>
            {
                var isBackPressure = queue.Count == queue.BoundedCapacity;

                if (isBackPressure)
                {
                    queue.Take(); // Dequeue an item to make space for the next one

                    // Fire back-pressure notification if defined
                    if (!isBackPressureNotified && backPressureNotification != null)
                    {
                        backPressureNotification();
                        isBackPressureNotified = true;
                    }
                }
                else
                {
                    isBackPressureNotified = false;
                }

                queue.Add(item);
            },
            exception => queue.CompleteAdding(),
            () => queue.CompleteAdding());

        token.Register(() => { subscription.Dispose(); });

        using (new CompositeDisposable(subscription, queue))
        {
            foreach (var item in queue.GetConsumingEnumerable())
            {
                yield return item;
            }
        }
    }