C# 如何使用反应式扩展与状态进行轮询?
关于使用Reactive()进行数据库轮询,已经有一个很好的问题 我有一个类似的问题,但有一个转折点:我需要在下一个请求中输入上一个结果的值。基本上,我想调查一下:C# 如何使用反应式扩展与状态进行轮询?,c#,system.reactive,rx.net,C#,System.reactive,Rx.net,关于使用Reactive()进行数据库轮询,已经有一个很好的问题 我有一个类似的问题,但有一个转折点:我需要在下一个请求中输入上一个结果的值。基本上,我想调查一下: interface ResultSet<T> { int? CurrentAsOfHandle {get;} IList<T> Results {get;} } Task<ResultSet<T>> GetNewResultsAsync<T>(int? pre
interface ResultSet<T>
{
int? CurrentAsOfHandle {get;}
IList<T> Results {get;}
}
Task<ResultSet<T>> GetNewResultsAsync<T>(int? previousRequestHandle);
还请注意,此版本允许在等待下一次迭代时收集
消息resultset
(例如,我想也许我可以使用扫描
将上一个结果集对象传递到下一次迭代)您的问题基本上归结为:有一个带有签名的扫描功能:
IObservable<TAccumulate> Scan<TSource, TAccumulate>(this IObservable<TSource> source,
TAccumulate initialValue, Func<TAccumulate, TSource, TAccumulate> accumulator)
考虑到这一点,我们可以对其进行一些修改,以合并减少功能:
public static IObservable<TAccumulate> MyObservableScan<TSource, TAccumulate>(this IObservable<TSource> source,
TAccumulate initialValue, Func<TAccumulate, TSource, IObservable<TAccumulate>> accumulator)
{
return source
.Publish(_source => _source
.Take(1)
.Select(s => accumulator(initialValue, s))
.SelectMany(async o => (await o.LastOrDefaultAsync())
.Let(m => _source
.MyObservableScan(m, accumulator)
.StartWith(m)
)
)
.Merge()
);
}
//Wrapper to accommodate easy Task -> Observable transformations
public static IObservable<TAccumulate> MyObservableScan<TSource, TAccumulate>(this IObservable<TSource> source,
TAccumulate initialValue, Func<TAccumulate, TSource, Task<TAccumulate>> accumulator)
{
return source.MyObservableScan(initialValue, (a, s) => Observable.FromAsync(() => accumulator(a, s)));
}
//Function to prevent re-evaluation in functional scenarios
public static U Let<T, U>(this T t, Func<T, U> selector)
{
return selector(t);
}
请注意,在测试中,我注意到如果累加器任务
/可观察
函数在源代码中花费的时间超过间隔,则可观察将终止。我不知道为什么。如果有人能纠正,我将不胜感激。我发现有一个超负荷的可观察。生成,这基本上起到了作用。主要缺点是它不能与async
一起工作
public static IObservable Generate(TState initialState、Func condition、Func iterate、Func resultSelector、Func timeSelector、IScheduler调度器)代码>
我传入null
作为初始状态。传入x=>true
作为我的条件(无休止地轮询)。在迭代
中,我根据传入的状态执行实际的轮询。然后在timeSelector
中返回轮询间隔
因此:
var resultSets=Observable.Generate(
//初始(空)结果
新结果集(),
//无休止的投票(直到取消订阅)
rs=>正确,
//每次轮询迭代
rs=>
{
//从以前的结果(可能是初始结果)获取版本
int?previousVersion=rs.CurrentVersionHandle;
//但问题是:它不能与异步方法一起工作:(
MessageResultSet MessageResultSet=ReadLateStMessageAsync(当前版本)。结果;
返回消息resultset;
},
//我们只关心在结果集中吐出消息
rs=>rs.消息,
//轮询间隔
时间跨度从分钟(1),
//运行每个迭代的计划程序
TaskPoolScheduler.Default);
返回结果集
//将消息列表投影到序列中
.SelectMany(messageList=>messageList);
另一个小缺点是整个结果集将持续到下一次迭代。问题中的版本允许对“消息”部分进行垃圾收集,因为我们只需要“版本”。
IObservable<TAccumulate> Scan<TSource, TAccumulate>(this IObservable<TSource> source,
TAccumulate initialValue, Func<TAccumulate, TSource, IObservable<TAccumulate>> accumulator)
public static IObservable<TAccumulate> MyScan<TSource, TAccumulate>(this IObservable<TSource> source,
TAccumulate initialValue, Func<TAccumulate, TSource, TAccumulate> accumulator)
{
return source
.Publish(_source => _source
.Take(1)
.Select(s => accumulator(initialValue, s))
.SelectMany(m => _source.MyScan(m, accumulator).StartWith(m))
);
}
public static IObservable<TAccumulate> MyObservableScan<TSource, TAccumulate>(this IObservable<TSource> source,
TAccumulate initialValue, Func<TAccumulate, TSource, IObservable<TAccumulate>> accumulator)
{
return source
.Publish(_source => _source
.Take(1)
.Select(s => accumulator(initialValue, s))
.SelectMany(async o => (await o.LastOrDefaultAsync())
.Let(m => _source
.MyObservableScan(m, accumulator)
.StartWith(m)
)
)
.Merge()
);
}
//Wrapper to accommodate easy Task -> Observable transformations
public static IObservable<TAccumulate> MyObservableScan<TSource, TAccumulate>(this IObservable<TSource> source,
TAccumulate initialValue, Func<TAccumulate, TSource, Task<TAccumulate>> accumulator)
{
return source.MyObservableScan(initialValue, (a, s) => Observable.FromAsync(() => accumulator(a, s)));
}
//Function to prevent re-evaluation in functional scenarios
public static U Let<T, U>(this T t, Func<T, U> selector)
{
return selector(t);
}
var o = Observable.Interval(TimeSpan.FromMinutes(1))
.MyObservableScan<long, ResultSet<string>>(null, (r, _) => Methods.GetNewResultsAsync<string>(r?.CurrentAsOfHandle))
var resultSets = Observable.Generate<ResultSet<IMessage>, IEnumerable<IMessage>>(
//initial (empty) result
new ResultSet<IMessage>(),
//poll endlessly (until unsubscription)
rs => true,
//each polling iteration
rs =>
{
//get the version from the previous result (which could be that initial result)
int? previousVersion = rs.CurrentVersionHandle;
//here's the problem, though: it won't work with async methods :(
MessageResultSet messageResultSet = ReadLatestMessagesAsync(currentVersion).Result;
return messageResultSet;
},
//we only care about spitting out the messages in a result set
rs => rs.Messages,
//polling interval
TimeSpan.FromMinutes(1),
//which scheduler to run each iteration
TaskPoolScheduler.Default);
return resultSets
//project the list of messages into a sequence
.SelectMany(messageList => messageList);