如何优化递归函数的反应式实现
本文关键字:递归函数 反应式 实现 优化 何优化 | 更新日期: 2023-09-27 18:24:09
我尝试使用Rx库在C#中创建一个具有动态间隔的自定义Reactive计时器。由于我在性能和行数方面都需要最优化的代码,所以我最终使用了递归方法。代码如下:
public static IObservable<TOut> GenerateAsync<TResult, TOut>(
Func<Task<TResult>> initialState,
Func<TResult, bool> condition,
Func<TResult, Task<TResult>> iterate,
Func<TResult, TimeSpan> timeSelector,
Func<TResult, TOut> resultSelector,
IScheduler scheduler = null)
{
var s = scheduler ?? Scheduler.Default;
return Observable.Create<TOut>(async obs =>
{
//You have to do your initial time delay here.
var init = await initialState();
//Process the result
obs.OnNext(resultSelector(init));
return s.Schedule(init, timeSelector(init), async (state, recurse) =>
{
//Check if we are done
if (!condition(state))
{
obs.OnCompleted();
return;
}
//Initiate the next request
state = await iterate(state);
//Process the result
obs.OnNext(resultSelector(state));
//Recursively schedule again
recurse(state, timeSelector(state));
});
});
}
这种方法的问题在于,由于它是递归的,因此存在巨大的堆栈增长。我针对定时器的使用情况测试了这种方法,它的内存使用量几乎是原来的两倍。
用于测试代码的链接,我曾获得内存使用测试。
如何在不失去使用能力的情况下优化此功能?
这看起来有点像任务和可观察对象的混合——仅可观察对象就足以表达。
要回答您的基本问题,需要创建一个具有可变时间段的间隔计时器,该计时器在计时器运行时提供。这可以表示为一个可观测值,它以TimeSpan
的可观测值作为输入,并返回tick作为输出,就像内置的Observable.Interval
一样。
static IObservable<long> MutableInterval(IObservable<TimeSpan> period, IScheduler scheduler)
{
return period.Select(timespan => Observable.Interval(timespan, scheduler))
.Switch()
.Scan(0L, (a, _) => a + 1);
}
这是一个缓慢下降期的测试:
var slowlyDecreasing =
Observable.Interval(TimeSpan.FromSeconds(1))
.StartWith(0)
.Select(p => TimeSpan.FromMilliseconds(1000 / (p + 1)))
.Do(p => Console.WriteLine("Period changed to {0}", p));
MutableInterval(slowlyDecreasing, Scheduler.Default).Subscribe(Console.WriteLine);