请教各位大侠,目前有如下需求不知如何实现:
数值A和数值B不停的比较,数值A为一个定值,数值B是通过远端采集过来的一个数值,当数值B在一定时间内与数值A不相等时,触发一个bool变量为1,
实际应用中,需要涉及到几十个这样的比较,考虑使用类做数值比较的延时判断,但是发现单次调用类导致数值B无法实时跟随远端采集过来的数据刷新(进入类后,使用调用类瞬时的数值B),这样类中的延时判断也就没有实际意义了,如果循环调用类,那延时判定时间如何累加又不知道如何实现了,
请各位大侠给个思路,新手上路,谢谢!
这种问题使用 Rx.Net 可以很方便的解决:
using System;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
namespace RxDemo
{
class Program
{
private static readonly Random Rnd = new Random(42);
private const int A = 1;
static void Main(string[] args)
{
var period = TimeSpan.FromSeconds(3);
var result = ObserveResult(period, samplePeriod: TimeSpan.FromSeconds(1));
using var sub = result.Subscribe(
x =>
{
if (x)
{
Console.WriteLine($"[{DateTime.Now:hh:mm:ss}] all B != A in " + period);
}
else
{
Console.WriteLine($"[{DateTime.Now:hh:mm:ss}] not all B != A in " + period);
}
});
Console.ReadKey();
}
static Task<int> FetchValueBAsync()
{
return Task.FromResult(Rnd.Next(0, 3));
}
static IObservable<int> ObserveB(TimeSpan samplePeriod)
{
return Observable.Timer(dueTime: TimeSpan.Zero, period: samplePeriod)
.SelectMany(_ => FetchValueBAsync());
}
static IObservable<bool> ObserveResult(TimeSpan period, TimeSpan samplePeriod)
{
return ObserveB(samplePeriod)
.Do(b => Console.WriteLine($"[{DateTime.Now:hh:mm:ss}] Fetched B: {b}")) // 记录一下 B 的值以及采样时间
.Buffer(period) // 把一段时间内的 B 的值打包成一个数组
.Select(x => x.All(b => b != A)); // 当每个数组中的所有结果为 true 时,表示这段时间所有的 B != A
}
}
}
样例输出:
[10:58:31] Fetched B: 2
[10:58:32] Fetched B: 0
[10:58:33] Fetched B: 0
[10:58:34] all B != A in 00:00:03
[10:58:34] Fetched B: 1
[10:58:35] Fetched B: 0
[10:58:36] Fetched B: 0
[10:58:37] not all B != A in 00:00:03
B 的值是远程采集的,不管是推送给你还是你主动去拉取,肯定会有一个采样频率,这个行为我用 ObserveB(TimeSpan samplePeriod)
来模拟。这个函数返回的是一个 IObservable<int>
,代表 B 的值随时间改变的序列。在你实际的代码中你需要自己实现这个函数。
ObserveResult(TimeSpan period, TimeSpan samplePeriod)
才是实现 “当数值B在一定时间内与数值A不相等时,触发一个bool变量为1” 的要点。这里的核心是 Buffer
操作符,用来将一段时间内的数据收集到一个数组中。
您的方式 Rx.Net,我还是第一次接触,我的好好消化消化,谢谢大侠的指点
//定义一个时间,用于存储上次A=B的时间
DateTime lastEqualTime;
//在B更新值后或者你自己以一定时间频率去触发
void AfterUpdateBOrSomeTime()
{
if (A = B)
{
lastEqualTime = DateTime.Now;
}
else
{
///当数值B在一定时间内与数值A不相等时
if (lastEqualTime - DateTime.Now > someFixedTimeSpan)
{
return true;
}
else
{
return false;
}
}
}
博问支持 markdown 代码高亮
大侠,您这个我么看懂,能在详细说下思路吗?
@dudu: 好的dudu大佬
@rossi1984: 修改了
@dudu: 大佬能留步指点一下吗?
@rossi1984: 建议先提供一下你目前的实现代码
@dudu: 回大佬
button_click事件触发标志位
timer_Tick //定时器循环执行
{
if(button_click_标志位)
{
if(A==B)
{
相等标志位=1;
不相等累计值=0;
}
else
{
不相等累计值 + =1;//累计,每次循环+1
}
if(不相等累计值 > 设定值 )
{
故障标志位=1;
button_click_标志位=0;
break;
}
}
}
如上是我最初想到的笨方法,考虑到应用会有很多,一个一个这样写,难以想象,楼下几位大侠的队列思路,也挺好,但是我没想通如何兼顾类的通用,以及保证数据的刷新,如何实现?
@dudu: 结贴前,大佬能不能给点指点,谢谢
条件:
A是一个定值,
B是一个不停取来的新数值,
一段时间内A!=B bool 标志=1
解决方法:
定义一个容器, DataTable 或 数组 或 队列 或 链表 或 map
收到一个B,就按队列放到容易器里面
每隔一段时间就在这个容器里判断这个值是否相同, 判断后清空已经处理过的接收数据
大侠,您把问题归纳的非常透彻,但是您说的方法,我想了许久,没有想出使用类的方式实现的办法,由于我这里需要这种比较的变量非常多,您能在费心讲讲吗?
这种有传输和运行,不能排除时间会有延迟,但是可以尽优化。
你的要求是判断不等就改状态,你考虑从多个端口过来,改一个状态? 如果是这样,可以考虑并行计算,只要不等就改状态,剩下没算完的也以不比了。
如果是多个端口过来是多个状态修改,也有并行计算有关,但是不上面一种情况,这个只是都需要计算完。