从实时数据流中搜索数据——算法2

本文介绍了一种针对实时数据流的高效搜索算法,通过改进数据比对方式,避免了传统算法中的缓存回溯,显著提升了搜索效率,特别是在处理大规模数据流时表现更佳。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目需要从实时单向数据流中读取和筛选数据,即当遇到标志数据时,执行某些操作。所有数据只能读一次,不能回溯。我们的场景是监听串口,然后根据监听结果,读取后续数据。

上午写了个算法程序:从实时数据流中搜索数据,监控实时数据流中的数据,发现数据时立即做出应对。然后,写完了之后,总觉得性能有缺陷。仔细考虑了一下,发现问题在于其数据搜索算法不太好:

1)从实时数据流中读入数据;

2)把数据加入缓存;

3)对比缓存和目标数据;

在那个算法中,需要维护一份(同目标数据一样大的)缓存,然后比较的时候,回溯缓存

我就是在纠结与这个缓存的问题,然后想了一个新的算法:

1)从实时数据流中读入数据;

2)比较数据和目标数据:

  1. 首字符匹配的,把结果加入队列中;
  2. 二字符后匹配的,继续;
  3. 二字符后不匹配的,从队列中删除;

经测试,性能提高超过一半。

上代码,先是适合实时数据流的版本:

        public static bool Search(System.IO.Stream stream, byte[] findBytes, int timeout)
        {
            var bytesLength = findBytes.Length;
            var matchQueue = new int[bytesLength];
            var matchCount = 0;

            var expired = false;
            var expires = DateTime.Now.AddMilliseconds(timeout);
            var timer = new System.Timers.Timer(10);
            timer.Elapsed += (sender, e) =>
            {
                expired = DateTime.Now > expires;
            };
            timer.Start();

            while (!expired)
            {
                // 从数据流中读取一个字符
                byte b = 0;
                try
                {
                    var n = stream.ReadByte();
                    // 若没有读到新数据,则继续尝试,直到超时
                    if (n < 0) continue;
                    else b = (byte)n;
                }
                catch
                {
                    continue;
                }
                // 递增匹配队列
                for (var i = 0; i < matchCount; i++)
                {
                    matchQueue[i]++;
                }
                // 如果匹配第一个字符,那么加入匹配队列中
                if (b == findBytes[0])
                {
                    matchQueue[matchCount++] = 0;
                }
                // 否则依次判断每一个队列中的匹配结果是否依旧匹配
                else
                {
                    var i = 0;
                    while (i < matchCount)
                    {
                        if (b == findBytes[matchQueue[i]])
                        {
                            // 当某一匹配结果匹配了全部字符,则返回结果
                            if (matchQueue[i] >= bytesLength - 1) 
                            {
                                timer.Stop();
                                timer.Close();
                                return true;
                            }
                            i++;
                        }
                        else
                        {
                            // 对于不再匹配的,从匹配队列中删除
                            for (var j = i; j < matchCount - 1; j++)
                            {
                                matchQueue[j] = matchQueue[j + 1];
                            }
                            matchCount--;
                        }
                    }
                }
            }

            timer.Stop();
            timer.Close();
            return false;
        }

然后是适合文件流的版本:

public static bool Search(System.IO.Stream stream, byte[] findBytes)
        {
            var bytesLength = findBytes.Length;
            var matchQueue = new int[bytesLength];
            var matchCount = 0;

            while (true)
            {
                // 从数据流中读取一个字符
                byte b = 0;
                try
                {
                    var n = stream.ReadByte();
                    if (n < 0) break;
                    else b = (byte)n;
                }
                catch
                {
                    break;
                }
                // 递增匹配队列
                for (var i = 0; i < matchCount; i++)
                {
                    matchQueue[i]++;
                }
                // 如果匹配第一个字符,那么加入匹配队列中
                if (b == findBytes[0])
                {
                    matchQueue[matchCount++] = 0;
                }
                // 否则依次判断每一个队列中的匹配结果是否依旧匹配
                else
                {
                    var i = 0;
                    while (i < matchCount)
                    {
                        if (b == findBytes[matchQueue[i]])
                        {
                            // 当某一匹配结果匹配了全部字符,则返回结果
                            if (matchQueue[i] >= bytesLength - 1) return true;
                            i++;
                        }
                        else
                        {
                            // 对于不再匹配的,从匹配队列中删除
                            for (var j = i; j < matchCount - 1; j++)
                            {
                                matchQueue[j] = matchQueue[j + 1];
                            }
                            matchCount--;
                        }
                    }
                }
            }

            return false;
        }

使用文件流测试了两个算法:

文件大小纯扫描文件耗时算法1耗时算法2耗时
100K3ms22ms10ms
1000M881ms4956ms1265ms

说明:

算法1,指的是从实时数据流中搜索数据文章所描述的算法;

算法2,指的是本文描述的算法;

纯扫描文件耗时,指的是打开文件,并逐一读入全部文件字节消耗的时间;

算法1耗时和算法2耗时,指的是使用算法程序搜索成功靠后的某一个字符串的时间;

100K的测试文件是ASCII的,1G的测试文件是Unicode的。

 

根据上表的测试结果,我对这个算法的性能还算满意,只是需要更多测试,以保证其实用性和稳健性,

 

以上是本文全部内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值