RX terminolgy:当有频繁的可观察通知时,RX运算符中的异步处理

时间:2018-03-21 20:59:25

标签: c# system.reactive rx.net backpressure

目的是在RX运算符中对稀缺资源进行一些异步工作,例如Select。当可观察通知的速率快于异步操作完成所需的时间时,会出现问题。

现在我真的解决了这个问题。我的问题是这个特定问题的正确术语是什么?它有名字吗?是背压吗?我所做的研究直到现在表明这是一种压力问题,但不一定是我理解的背压。我找到的最相关的资源是这些: https://github.com/ReactiveX/RxJava/wiki/Backpressure-(2.0) http://reactivex.io/documentation/operators/backpressure.html

现在到实际代码。假设有稀缺资源而且它是消费者。在这种情况下,在使用资源时抛出异常。请注意,不应更改此代码。

public class ScarceResource
{
    private static bool inUse = false;

    public async Task<int> AccessResource()
    {
        if (inUse) throw new Exception("Resource is alredy in use");

        var result = await Task.Run(() =>
        {
            inUse = true;
            Random random = new Random();
            Thread.Sleep(random.Next(1, 2) * 1000);
            inUse = false;

            return random.Next(1, 10);
        });

        return result;
    }
}

public class ResourceConsumer
{
    public IObservable<int> DoWork()
    {
        var resource = new ScarceResource();
        return resource.AccessResource().ToObservable();
    }
}

现在,这是一个使用资源的天真实现的问题。抛出错误是因为通知的速度比消费者运行速度快。

private static void RunIntoIssue()
{
    var numbers = Enumerable.Range(1, 10);
    var observableSequence = numbers
        .ToObservable()
        .SelectMany(n =>
        {
            Console.WriteLine("In observable: {0}", n);
            var resourceConsumer = new ResourceConsumer();
            return resourceConsumer.DoWork();
        });

    observableSequence.Subscribe(n => Console.WriteLine("In observer: {0}", n));
}

使用以下代码解决问题。我通过将完整的BehaviorSubject与Zip运算符结合使用来减慢处理速度。基本上,这段代码的作用是采用顺序方法而不是并行方法。

private static void RunWithZip()
{
    var completed = new BehaviorSubject<bool>(true);
    var numbers = Enumerable.Range(1, 10);
    var observableSequence = numbers
        .ToObservable()
        .Zip(completed, (n, c) =>
        {
            Console.WriteLine("In observable: {0}, completed: {1}", n, c);
            var resourceConsumer = new ResourceConsumer();
            return resourceConsumer.DoWork();
        })
        .Switch()
        .Select(n =>
        {
            completed.OnNext(true);
            return n;
        });

    observableSequence.Subscribe(n => Console.WriteLine("In observer: {0}", n));
    Console.Read();
}

问题 这是背压,如果不是,它还有另一个术语吗?

1 个答案:

答案 0 :(得分:1)

您基本上实现了一种锁定形式或互斥锁。你的代码导致背压,它并没有真正处理它。

想象一下,如果您的源不是生成器函数,而是一系列数据推送。数据推送以每毫秒的恒定速率到达。它需要10 Millis来处理每一个,你的代码强制进行串行处理。这会导致背压:Zip会无限地排队未处理的数据刷,直到内存不足为止。