开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 333|回复: 12
收起左侧

[易语言纯源码] 固定数组线程安全键取索引 替代小量键值表场景

[复制链接]
结帖率:60% (3/5)
发表于 昨天 02:49 | 显示全部楼层 |阅读模式   广东省深圳市
分享源码
界面截图: -
是否带模块: -
备注说明: -

必须强调的安全前提

这个方案的线程安全是有严格前提的,破一条就可能出问题:
单写原则:只能有一个线程调用 有序尾插键,多写必须加临界区;
有序原则:新键的字典序必须 ≥ 当前数组最后一个键,例程里的校验建议保留;
不扩容原则:初始化一次性分配足够容量,运行中绝不调用 重定义数组();
顺序原则:写入永远是「先写元素,后更计数」,顺序不能颠倒;

只增不删、严格递增的场景下,这个方案的性能和简洁度都是最优的。


  
窗口程序集名保 留  保 留备 注
窗口程序集_启动窗口   
变量名类 型数组备 注
键数组文本型2000 
有效成员数整数型当前有效元素数量,初始为0
停止测试逻辑型线程停止标记
总cha询次数整数型统计总cha询量
错误次数整数型统计cha询错误次数
统计许可区整数型仅用于统计变量加锁,不影响核心cha询逻辑

子程序名返回值类型公开备 注
__启动窗口_创建完毕  

子程序名返回值类型公开备 注
_按钮1_被单击  
变量名类 型静态数组备 注
i整数型 
' 初始化:预填充1000条有序基础数据
有效成员数 = 0
计次循环首 (1000, i)
键数组 [i]“key_”文本补零 (到文本 (i), 4)
有效成员数 = 有效成员数 + 1
计次循环尾 ()
' 重置测试状态
停止测试 = 假
总cha询次数 = 0
错误次数 = 0
统计许可区 = 创建进入许可证 ()
' 启动8个并发读线程
计次循环首 (8, i)
启动线程 (&读线程工作, , )
计次循环尾 ()
' 启动1个写线程
启动线程 (&写线程工作, , )
' 持续测试10秒
延时 (10000)
停止测试 = 真
延时 (500)  ' 等待所有线程退出
' 输出结果
信息框 (“多线程安全验证完成”#换行符#换行符“总cha询次数:”到文本 (总cha询次数)#换行符“错误次数:”到文本 (错误次数)#换行符“最终有效成员数:”到文本 (有效成员数), 0, “验证结果”, )
子程序名返回值类型公开备 注
读线程工作 
变量名类 型静态数组备 注
目标序号整数型 
目标键文本型 
查到下标整数型 
置随机数种子 ()
判断循环首 (取反 (停止测试))
' 随机生成一个已存在范围内的键
目标序号 = 取随机数 (1, 有效成员数)
目标键 = “key_”文本补零 (到文本 (目标序号), 4)
' 核心:无锁二分cha询
查到下标 = 二分查找下标 (目标键)
' 校验结果正确性
如果真 (查到下标 = -1 键数组 [查到下标] ≠ 目标键)
' 仅统计加锁,不影响核心cha询性能
进入许可区 (统计许可区)
错误次数 = 错误次数 + 1
退出许可区 (统计许可区)
' 统计总cha询量
进入许可区 (统计许可区)
总cha询次数 = 总cha询次数 + 1
退出许可区 (统计许可区)
判断循环尾 ()
子程序名返回值类型公开备 注
写线程工作 
变量名类 型静态数组备 注
i整数型 
新键文本型 
' 从第1001个键开始插入,一直插到第3000个
计次循环首 (2000, i)
如果真 (停止测试)
跳出循环 ()
新键 = “key_”文本补零 (到文本 (1000 + i), 4)
有序尾插键 (新键)
' 1ms插入一个,模拟低频新增,同时给读线程留足并发窗口
延时 (1)
计次循环尾 ()
子程序名返回值类型公开备 注
文本补零文本型 
参数名类 型参考可空数组备 注
原文本文本型
总长度整数型
变量名类 型静态数组备 注
补零数整数型 
补零数 = 总长度 - 取文本长度 (原文本)
如果真 (补零数 ≤ 0)
返回 (原文本)
返回 (取重复文本 (补零数, “0”) + 原文本)
子程序名返回值类型公开备 注
二分查找下标整数型 找到返回下标,未找到返回-1;读线程全程无锁
参数名类 型参考可空数组备 注
目标键文本型
变量名类 型静态数组备 注
整数型 
整数型 
中间整数型 
比较结果整数型 
当前有效数整数型 
' ========== 关键安全细节 ==========
' 只读一次有效成员数到局部变量,本次cha询全程使用该快照
' 避免写入过程中计数变化导致越界,也保证本次cha询范围一致
当前有效数 = 有效成员数
左 = 1
右 = 当前有效数
判断循环首 (左 ≤ 右)
中间 (左 + 右) ÷ 2
比较结果 = 文本比较 (键数组 [中间], 目标键, )  ' 区分大小写按需调整
如果真 (比较结果 = 0)
返回 (中间)
如果真 (比较结果 < 0)
左 = 中间 + 1
如果真 (比较结果 > 0)
右 = 中间 - 1

判断循环尾 ()
返回 (-1)
子程序名返回值类型公开备 注
有序尾插键逻辑型 仅允许单个写线程调用
参数名类 型参考可空数组备 注
新键文本型
变量名类 型静态数组备 注
最后位置整数型 
最后位置 = 有效成员数
' 1. 容量硬校验:超过预分配直接失败,绝不触发扩容
如果真 (最后位置 ≥ 取数组成员数 (键数组))
返回 ()
' 2. 有序性校验:确保新键 ≥ 最后一个键,维持数组有序
如果真 (最后位置 > 0 文本比较 (新键, 键数组 [最后位置], ) < 0)
返回 ()  ' 新键更小,拒绝插入,避免破坏有序性
' ========== 严格执行顺序:先写元素,后更计数 ==========
键数组 [最后位置 + 1] = 新键
有效成员数 = 最后位置 + 1
返回 ()


i支持库列表   支持库注释   
EThread多线程支持库


结帖率:60% (3/5)

签到天数: 16 天

 楼主| 发表于 昨天 03:27 | 显示全部楼层   广东省深圳市

从性能、稳定性、安全性、灵活性等核心维度,对「有序尾插+无锁二分」和「哈希表+临界区」做完整对比,最后给出明确选型建议。


一、核心指标总览表

对比维度 有序尾插 + 无锁二分查找 哈希表 + 临界区
平均读延迟 ~0.1~0.3μs ~0.3~0.8μs
延迟稳定性(P99) 极好,无任何抖动 一般,锁竞争会产生毛刺
写性能(单写) 极致,O(1) 指针赋值 较好,O(1) 但有加锁开销
线程安全强度 前提依赖型安全(约束严格) 强安全(正确加锁则绝对安全)
功能灵活性 极弱,仅支持有序尾插 强,支持任意增删改
内存占用 & 缓存友好度 极低,连续内存,缓存命中率高 中等,桶结构,内存碎片化稍高
实现可控性 完全自研,逻辑透明,易排查 依赖第三方模块,黑盒属性强
维护容错率 低,违反前提即出隐蔽bug 高,通用方案不易踩坑

二、分维度详细对比

1. 读性能:绝对速度差距小,稳定性差距巨大

这是量化场景最核心的差异,两者平均延迟都在微秒级,日常使用感知不到,但延迟抖动(P99/P999)天差地别

有序尾插 + 无锁二分

  • 运算逻辑:1000条数据最多执行10次文本比较,O(logn) 复杂度,常数项极低;
  • 同步开销:,没有任何锁、原子操作、内存屏障,纯用户态内存读取;
  • 延迟表现:延迟极其平稳,平均和最大值几乎一致,不会出现突发卡顿。
  • 额外优势:数组内存连续,CPU缓存命中率极高,高频访问下实际表现优于理论复杂度。

哈希表 + 临界区

  • 运算逻辑:平均O(1),但包含「文本哈希计算 + 桶定位 + 冲突链遍历」三步。短文本的哈希计算开销,本身就相当于3~5次文本比较;如果哈希函数一般、冲突较多,实际运算量会反超二分查找。
  • 同步开销:每次查询都必须走「进入许可区 → 查询 → 退出许可区」。易语言的许可区封装的是Windows CRITICAL_SECTION,无竞争时开销约几十纳秒;但多线程并发下一旦出现锁等待,会直接切换到内核态,延迟飙升到几微秒甚至几十微秒,产生明显的延迟毛刺。
  • 延迟表现:平均延迟尚可,但高并发下P99延迟会是平均的5~10倍,对于对时序敏感的量化策略来说,这种不可控的抖动风险远大于几纳秒的平均速度差异。

关键结论:1000条规模下,无锁二分的读性能不仅更快,更重要的是延迟完全可预测、无毛刺,这是高频交易系统最看重的特性。

2. 写性能:尾插方案有压倒性优势

有序尾插 + 无锁二分

  • 写入就是一次文本指针赋值 + 一次整数自增,纯O(1)操作,没有任何额外开销,单线程下写入延迟在纳秒级;
  • 无锁,单写场景下不存在任何竞争。

哈希表 + 临界区

  • 写入需要哈希计算、桶插入、处理冲突,本身运算量就更高;
  • 必须加锁,哪怕单写没有竞争,加解锁的固定开销也远大于纯指针赋值;
  • 如果没有预分配桶容量,运行中触发扩容会导致毫秒级卡顿,对量化场景是致命风险(必须初始化时预分配桶数)。

3. 线程安全:一个靠约束,一个靠机制

这是两者最本质的区别:安全的来源完全不同。

有序尾插 + 无锁二分

  • 安全是有前提的,必须同时满足:单写线程、键严格递增尾插、全程不扩容、先写元素后更计数、运行在x86/x64平台。
  • 所有前提都遵守时,是100%安全的;但只要违反其中一条,就会出现隐蔽bug——比如插了一个更小的键导致二分出錯、多写导致计数错乱、扩容导致内存崩溃。
  • 风险特点:不出问题则已,一出问题就是极难复现的偶发错误,排查成本极高。

哈希表 + 临界区

  • 安全是靠锁机制保证的,只要所有读写操作都正确包裹在临界区内,不管增删改、不管多少线程、不管键的顺序如何,都是绝对线程安全的。
  • 风险特点:如果出问题,基本是锁漏加、加锁范围不对这种明显bug,排查相对简单;不会出现“偶尔抽风”的玄学问题。

4. 功能灵活性与适用边界

有序尾插 + 无锁二分

  • 功能极度受限:只能在末尾追加递增的键,不能删除、不能修改已有键、不能随机插入中间键;
  • 适用场景非常窄:仅适合键天然递增、只增不删的场景,比如按顺序加载的固定品种代码。
  • 后续业务一旦需要支持删除、乱序新增,整个方案直接作废,必须重构。

哈希表 + 临界区

  • 通用型键值表,增删改查全支持,键的顺序、数量变化都无所谓;
  • 业务迭代灵活,后续不管是加删除、改键值、扩数量,都不用改架构,直接用就行。

5. 易语言生态的额外差异

  • 二分查找:纯原生代码,逻辑完全自己掌控,没有第三方依赖,不会有模块版本兼容、内存泄漏、隐藏bug等问题,打包也干净。
  • 哈希表:依赖第三方模块(如精易模块、各类哈希支持库),易语言生态里哈希实现质量参差不齐:
    • 劣质实现哈希冲突严重,1000条数据的实际查询性能反而不如二分;
    • 部分实现对文本引用计数处理不当,高频场景下可能出现内存泄漏或崩溃;
    • 闭源模块出了问题无法排查,只能换方案。

三、最终选型建议

选「有序尾插 + 无锁二分」的场景

如果以下条件你都能长期满足,这个方案是极致最优解:

  1. 能100%保证键永远按字典序递增追加,不会出现乱序插入;
  2. 业务确定只增不删、不改已有键值,后续不会有删除/修改需求;
  3. 只有一个写线程,初始化一次性分配足容量,全程不扩容;
  4. 对延迟稳定性要求极高,不能接受任何锁竞争导致的毛刺。

这是典型的“窄场景极致优化”,符合你的使用规则的话,性能和稳定性都碾压哈希表方案。

选「哈希表 + 临界区」的场景

只要满足以下任意一条,优先选哈希表+临界区,更稳妥:

  1. 无法保证键永远递增,可能需要随机插入中间键;
  2. 后续可能需要删除、修改键值对,功能有不确定性;
  3. 可能存在多个写线程,或者不想被“单写、有序、不扩容”这些规则束缚;
  4. 追求通用、稳妥、低维护成本,不想为了微秒级的优化承担逻辑风险。
回复 支持 反对

使用道具 举报

签到天数: 14 天

发表于 昨天 21:52 | 显示全部楼层   江苏省连云港市
感谢分享
回复 支持 反对

使用道具 举报

结帖率:100% (3/3)

签到天数: 4 天

发表于 昨天 18:37 | 显示全部楼层   广东省深圳市
学习一下
回复 支持 反对

使用道具 举报

签到天数: 12 天

发表于 昨天 16:43 | 显示全部楼层   安徽省合肥市
感谢大神分享~!  
回复 支持 反对

使用道具 举报

结帖率:100% (49/49)

签到天数: 5 天

发表于 昨天 15:55 | 显示全部楼层   江西省南昌市
我了个小量二分查找,定长+有序锁死了应用场景,终究是不成熟的方案,不如老老实实用哈希表
回复 支持 反对

使用道具 举报

结帖率:80% (4/5)
发表于 昨天 13:55 | 显示全部楼层   山东省潍坊市
已经顶贴,感谢您对论坛的支持!
回复 支持 反对

使用道具 举报

结帖率:50% (1/2)

签到天数: 11 天

发表于 昨天 13:51 | 显示全部楼层   广东省汕头市
感谢大神分享~!
回复 支持 反对

使用道具 举报

结帖率:0% (0/2)

签到天数: 13 天

发表于 昨天 11:07 | 显示全部楼层   广西壮族自治区玉林市
感谢分享
回复 支持 反对

使用道具 举报

结帖率:93% (78/84)

签到天数: 9 天

发表于 昨天 10:45 | 显示全部楼层   福建省宁德市
感谢分享
回复 支持 反对

使用道具 举报

结帖率:96% (498/518)

签到天数: 13 天

发表于 昨天 10:27 | 显示全部楼层   内蒙古自治区乌海市
感谢分享
回复 支持 反对

使用道具 举报

签到天数: 15 天

发表于 昨天 10:12 | 显示全部楼层   河北省石家庄市
感谢分享
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报QQ: 793400750,邮箱:wp@125.la
网站简介:精易论坛成立于2009年,是一个程序设计学习交流技术论坛,隶属于揭阳市揭东区精易科技有限公司所有。
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备2025452707号) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表