如何优化递归函数的 Reactive 实现
How to Optimize Reactive implementation of recursive function
我尝试使用 Rx 库在 C# 中创建具有动态间隔的自定义反应式计时器。因为我需要在性能和否方面都进行最优化的代码。我最终使用递归方法的行数。代码如下:
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));
});
});
}
这种方法的问题在于,由于它是递归的,因此会出现巨大的堆栈增长。我针对计时器使用情况测试了这种方法,它的内存使用量几乎翻了一番。
Link 用于测试代码,我用于获取内存使用测试。
如何在不失去其使用能力的情况下优化此功能?
这似乎是任务和 Observable 的大杂烩 - 仅 Observable 就足以表达。
回答您的基本问题 - 创建一个具有可变时间段的间隔计时器,该时间段在计时器运行时提供。这可以表示为一个 observable,它将 TimeSpan
的 observable 作为输入,returns ticks 作为输出,很像 built-in 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);
我尝试使用 Rx 库在 C# 中创建具有动态间隔的自定义反应式计时器。因为我需要在性能和否方面都进行最优化的代码。我最终使用递归方法的行数。代码如下:
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));
});
});
}
这种方法的问题在于,由于它是递归的,因此会出现巨大的堆栈增长。我针对计时器使用情况测试了这种方法,它的内存使用量几乎翻了一番。
Link 用于测试代码,我用于获取内存使用测试。
如何在不失去其使用能力的情况下优化此功能?
这似乎是任务和 Observable 的大杂烩 - 仅 Observable 就足以表达。
回答您的基本问题 - 创建一个具有可变时间段的间隔计时器,该时间段在计时器运行时提供。这可以表示为一个 observable,它将 TimeSpan
的 observable 作为输入,returns ticks 作为输出,很像 built-in 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);