rx.net中的背压问题

时间:2019-07-03 02:28:15

标签: c# rx.net backpressure

我想从CSV文件中读取行并使用RX.Net进行一些转换,我想进行批量更新并每250毫秒发送一次更新

public static IEnumerable<string> ReadCSV(string filePath)
{
    var reader = new StreamReader(File.OpenRead(filePath));
    while (!reader.EndOfStream)
    {
        var line = reader.ReadLine();
        yield return line;
    }
}

var rows = ReadCSV("filePath").ToObservable();

rows
    .Buffer(50)
    .Zip(Observable.Interval(
        TimeSpan.FromMilliseconds(250)), (res, _) => res)
    .Subscribe(lines =>
        {
            //do something
        });

我使用的csv文件的大小约为80mb,但控制台项目的大小为1gb。

这里发生的是Zip正在等待两个序列发出信号。 CSV序列可以非常快速地提供数据,因此它将批处理更新存储在内存中并等待其他序列。

更糟糕的是,即使正在处理所有更新,也不释放内存。如果我删除了Zip,则内存看起来非常好,似乎在处理批处理时正在释放内存(整个应用整个过程大约需要20mb)。

两个问题

  1. 有没有办法告诉可观察到的我想暂停读取,直到处理上一个(在我的情况下是缓冲行)。

  2. 为什么在处理所有更新后不释放内存,有没有办法避免这种情况?

2 个答案:

答案 0 :(得分:0)

我设法找到问题1的解决方案。

rows
    .Buffer(50)
    .Select(lines =>
    {
        Thread.Sleep(250);
        return lines;
    }
    .Subscribe(lines =>
        {
            //do something
        });

整个过程是同步的,所以当我执行Thread.Sleep时,可观察对象也会停止读取数据。

但这可能不是一个好答案。

答案 1 :(得分:0)

我无法重新创建您的内存使用问题。我使用了50mb的文件。 但是,我想您可能会遇到麻烦,就是.ToObservable()尽可能快地从IEnumerable中提取数据。

那么为什么不只是通过扩展方法来减慢IEnumerable的速度(从磁盘中拉出数据的速度)呢?

(示例中使用的.Buffer()的{​​{1}}运算符在Ix.Net中可用)。

像这样:

IEnumerable

(在C#8中,可以使该方法异步并使用ReadCSC() .Buffer(50) .SlowDown(250) .ToObservable() etc. ... public static IEnumerable<IList<string>> SlowDown(this IEnumerable<IList<string>> source, int milliSeconds) { foreach(var item in source) { yield return item; Thread.Sleep(milliSeconds); } } 而不是Task.Delay,这样就不会阻塞线程。)

这样,以较低的速度从磁盘读取数据。如果能解决您的内存问题,我不知道。