news 2026/9/28 4:43:26

〖共创稿事节〗HarmonyOS 7 新特性实战(13):在模拟器验证 FAST 四线程索引与热点插入

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
〖共创稿事节〗HarmonyOS 7 新特性实战(13):在模拟器验证 FAST 四线程索引与热点插入

先跑通一轮有确定答案的实验

import{runFastExperiment}from'libspatial_audio.so';// 在页面异步操作中等待结果,避免阻塞 UI 线程。constresult:string=awaitrunFastExperiment(19);

Demo 已在 API 26 模拟器调用系统libfast_ads.so,没有用普通容器替代 FAST。入口位于 FAST 实验页,Native 实验位于 Native 实验模块。打开“19/20 FAST 正确性实验”,点击“19 运行四线程哈希表”,页面会输出普通散列和全碰撞两轮结果。

这轮固定 1024 个键、4 个线程。每个线程操作自己的键集合,阶段之间等待全部线程退出,再核对容器数量。插入阶段必须有 1024 条;更新后检查返回的旧值指针与查到的新值指针;删除偶数键后必须剩 512 条,并逐项确认已删除键查询返回不存在。第二轮让全部键返回相同哈希,继续执行同一组检查。

热点键另作实验:4 个线程对同一新键调用TryInsert,要求恰好一个成功,其余返回已存在。这里没有规定哪个线程获胜,也没有把一次执行顺序误认为容器承诺。

auto code = tryInsert(handle, &hotKey, &values[t]); if (code == FAST_ERROR_CODE_SUCCESS) ++winners; else if (code != FAST_ERROR_CODE_KEY_EXISTS) ++errors;

tryInsert是由dlsym取得的HMS_FAST_ConcurrentHashmap_TryInsert函数指针,类型直接取自配套 SDK 声明。按需加载让缺少 FAST 库时返回具体错误,而不阻止其他实验页面启动。

两轮均通过;截图里的端到端数值是单次页面调用耗时,包含任务调度,不能作为 FAST 相对普通容器的加速比。当前没有完成互斥锁容器的性能对照,也没有声称证明任意线程交错下的所有并发性质。

真机上的普通散列与全碰撞

2026-09-20,在 HBN-AL80(API 26)通过相同页面入口连续运行两次。每次均回读 normal: PASS 与 collision: PASS,1024 个键、4 个线程,删除后 remaining=512,热点插入 winner=1。页面端到端耗时分别为 39 ms、34 ms。

这些结果覆盖固定键集的插入、查找、更新、删除和热点争抢。两次运行没有控制温度、频率或系统负载,也没有对照容器,故不据此推导吞吐量或加速比。截图底部仍保留旧版关于模拟器性能的通用提示,采集设备为上述真机。

补一次前台重复执行,先确认固定用例不会偶发失效

2026-09-18 在可见的 API 26 模拟器ArticleLabAPI26Fresh中,连续触发同一个页面入口 5 次。每次都走完普通散列、全部键碰撞和热点TryInsert三部分;布局快照均记录normal: PASS、collision: PASS与winner=1。端到端耗时依次为 258、154、94、97、125 ms,范围为 94–258 ms。

这组复跑证据可在 配套汇总记录 与同名前缀的 5 份布局快照中复查。它只覆盖固定的 1024 键、4 线程有限任务,且端到端时间包含 ArkTS 调用和任务调度;现有证据只支持“固定正确性用例连续通过”,不支持报告吞吐量、延迟百分位或比较 FAST 与受锁普通容器的性能。

2026-09-23 在 HBN-AL80(API 26)再运行一次当前包:普通散列与全碰撞都回读 PASS,均为keys=1024、threads=4、remaining=512、winner=1,页面端到端为 38 ms。该单次结果只确认固定正确性集没有在当前真机上偶发失败,不用于性能比较。

让容器先释放,再回收数据

FAST 只保存键值指针,数据所有权仍在调用者。Demo 先为整轮数据分配定长数组,再创建容器;插入后不调整数组大小。Native 异步任务内部启动线程,所有线程 join 后再销毁容器,最后释放数组。更新前后的值都保留到实验结束,避免另一线程读到失效内存。

std::vector<uint64_t> keys(count), values(count), updates(count); FAST_ConcurrentHashmapHandle handle = nullptr; Require(create(&handle, Hash, Equal, 1.0f, 16) == FAST_ERROR_CODE_SUCCESS && handle, "Create failed"); std::unique_ptr<void, decltype(destroy)> guard(handle, destroy);

页面离开后不再更新页面状态,后台任务继续完成这组有限工作并释放容器;这里没有强行终止持锁线程。模块限制同一时间只能执行一个 FAST 实验,连续点击不会堆积无限任务。

后续扩大实验时保留的约束

展品资源扫描、图片解码和页面查询同时发生时,多个线程可能争用同一份索引。把普通容器换成并发容器看起来直接,但如果键和值的生命周期没有理清,读得更快也可能读到已经释放的数据。

FAST Kit 提供并发哈希表 Native 能力。本地头文件fast_ads_concurrent_hashmap.h的基础接口起始版本为 6.1.1(API 24)。鸿蒙 7 工程先完成基础正确性检查,性能对照留作后续扩展,因此不将该接口描述为 API 26 首次新增。

先明确索引保存什么

第一版只存展品 ID 到轻量资源状态的映射,不把 UI 对象、PixelMap 或页面回调直接塞进容器。键在插入后必须保持稳定,值的更新方式和所有权应在适配层固定。

struct ExhibitKey { uint64_t id; }; struct ExhibitValue { uint32_t resourceVersion; uint32_t state; };

这是业务数据结构。FAST 接口使用句柄及键值指针,具体是否复制、如何回调、什么时候释放,必须按所选函数合同实现。不能因为容器并发安全,就认为任意外部指针都能无条件共享。

哈希相同不代表键相等

哈希函数决定桶分布,键相等函数决定是否是同一条记录。两个回调必须保持一致:相等键产生相同哈希,不相等键也可能碰撞。测试中应故意制造大量碰撞,检查结果正确性与性能退化。

字符串键若使用外部缓冲,缓冲内容变化会破坏查找语义。可以在写入前转换成稳定业务 ID,或由索引适配层明确拥有不可变副本,避免读取线程访问页面临时字符串。

原子单步不等于组合事务

“查询不存在,然后插入”包含两个动作,中间可能有另一个线程插入。是否可以用库提供的条件更新或原子操作,需要查看实际接口;没有相应能力时,应在应用层为组合规则加同步。

同理,更新资源版本与更新状态若必须同时可见,就不要拆成两个无关联写入。可以构造完整值后替换,或使用明确的保护机制,避免读到半更新状态。

基线要有同样的正确性要求

对照组可以使用受锁保护的普通容器。两组必须处理同样的插入、查询、更新和删除规则,不能让对照组额外复制数据,而实验组省略所有权管理后宣称更快。

固定随机种子 → 生成带线程标识的操作 → 无冲突阶段核对确定结果 → 冲突阶段记录调用/返回及观测值 → 按库承诺的并发语义校验 → 再统计性能

随机种子固定不代表线程交错固定。两个线程同时写同一个键,合法最终值可能不同,不能简单要求它与某次串行执行逐项一致。第一组让线程操作互不重叠的键,并用阶段屏障核对最终结果;第二组专门制造冲突,记录每次调用与返回区间,按库声明的一致性语义检查允许的结果。若库承诺线性化,可对小规模历史检查是否存在满足实时先后关系的合法串行排列;没有这项承诺时不擅自提高或降低判定标准。

测试读多写少、读写均衡、热点键竞争和碰撞四类负载。线程数逐步增加,记录曲线而不是只比较一个点。小数据集可能看不到收益,跨语言传参与内存分配反而占主要时间。

删除与退出是生命周期试金石

删除后旧读取者是否仍持有值,需要由接口的并发访问语义决定。不得在删除返回后就无条件释放仍可能被其他线程使用的外部对象。关闭索引前先停止新请求,等待工作线程结束,再销毁句柄与业务数据。

页面离开不能直接销毁后台线程仍在访问的索引。将容器服务与页面分离,并使用明确的关闭状态,有助于避免退出路径中的悬空指针。

用规模证明选择是否合适

最小 Demo 提供数据规模、线程数与负载类型配置,输出正确性结果、操作数和耗时。性能测试放在支持设备上,模拟器可用于接口与基础行为检查,但不能直接代表真机性能。

若实际图鉴只有几百条静态记录,普通不可变映射可能已经足够。并发哈希表更值得用于多线程持续更新的索引;选型结论应由真实访问模式决定。

第一轮限制值对象的生存期

为先分离容器正确性与回收问题,测试数据可在整轮实验期间保持有效,待线程全部退出后统一释放。这个保守基线会占用更多内存,但能避免一开始把查找错误与悬空指针混淆。之后单独增加并发删除与回收实验,不能把基线直接作为长期服务的内存策略。

访问模式可先选择的结构
只读小图鉴不可变映射
少量写入、实现成本敏感受锁保护的普通容器
多线程持续读写按真实负载比较 FAST 并发容器

参考:FAST 相关官方课程入口、API 26 开发套件。函数签名和所有权以 FAST Native 头文件为准。

官方支持范围:FAST Kit 简介。

四线程实验怎样收敛到可检查的阶段

下面 C++ 片段来自容器实验。外部键值数组在整个实验期间保持地址稳定,每个阶段等待工作线程结束后再检查数量与内容。碰撞测试替换散列函数,热点 TryInsert 使用原子计数统计赢家。

std::string HashmapExperiment() { Library library("libfast_ads.so"); auto create = library.Get<decltype(&HMS_FAST_ConcurrentHashmap_Create)>("HMS_FAST_ConcurrentHashmap_Create"); auto destroy = library.Get<decltype(&HMS_FAST_ConcurrentHashmap_Destroy)>("HMS_FAST_ConcurrentHashmap_Destroy"); auto insert = library.Get<decltype(&HMS_FAST_ConcurrentHashmap_Insert)>("HMS_FAST_ConcurrentHashmap_Insert"); auto find = library.Get<decltype(&HMS_FAST_ConcurrentHashmap_Find)>("HMS_FAST_ConcurrentHashmap_Find"); auto erase = library.Get<decltype(&HMS_FAST_ConcurrentHashmap_Erase)>("HMS_FAST_ConcurrentHashmap_Erase"); auto size = library.Get<decltype(&HMS_FAST_ConcurrentHashmap_Size)>("HMS_FAST_ConcurrentHashmap_Size"); auto tryInsert = library.Get<decltype(&HMS_FAST_ConcurrentHashmap_TryInsert)>("HMS_FAST_ConcurrentHashmap_TryInsert"); std::ostringstream result; for (bool collision : {false, true}) { constexpr size_t count = 1024; // 指针存入容器后不再调整数组大小;线程退出并销毁容器后才释放数组。 std::vector<uint64_t> keys(count), values(count), updates(count); for (size_t i = 0; i < count; ++i) { keys[i] = i; values[i] = i * 3; updates[i] = i * 7; } FAST_ConcurrentHashmapHandle handle = nullptr; Require(create(&handle, collision ? CollisionHash : Hash, Equal, 1.0f, 16) == FAST_ERROR_CODE_SUCCESS && handle, "Create failed"); std::unique_ptr<void, decltype(destroy)> guard(handle, destroy); std::atomic<size_t> errors{0}; Parallel([&](size_t t) { for (size_t i = t; i < count; i += 4) { if (insert(handle, &keys[i], &values[i], nullptr) != FAST_ERROR_CODE_SUCCESS) ++errors; } }); Require(errors == 0 && size(handle) == count, "Insert/size mismatch"); Parallel([&](size_t t) { for (size_t i = t; i < count; i += 4) { void* value = nullptr; if (find(handle, &keys[i], &value) != FAST_ERROR_CODE_SUCCESS || value != &values[i]) ++errors; void* old = nullptr; if (insert(handle, &keys[i], &updates[i], &old) != FAST_ERROR_CODE_KEY_EXISTS || old != &values[i]) ++errors; } }); Require(errors == 0, "Find/update mismatch"); Parallel([&](size_t t) { for (size_t i = t; i < count; i += 4) { void* value = nullptr; if (find(handle, &keys[i], &value) != FAST_ERROR_CODE_SUCCESS || value != &updates[i]) ++errors; if (i % 2 == 0 && erase(handle, &keys[i], nullptr, nullptr) != FAST_ERROR_CODE_SUCCESS) ++errors; } }); Require(errors == 0 && size(handle) == count / 2, "Erase/size mismatch"); for (size_t i = 0; i < count; i += 2) { void* value = nullptr; Require(find(handle, &keys[i], &value) == FAST_ERROR_CODE_KEY_NOT_EXISTS, "Erased key still present"); } // 四个线程争抢同一新键,TryInsert 必须恰好有一个成功。 uint64_t hotKey = count + 1; std::atomic<size_t> winners{0}; Parallel([&](size_t t) { auto code = tryInsert(handle, &hotKey, &values[t]); if (code == FAST_ERROR_CODE_SUCCESS) ++winners; else if (code != FAST_ERROR_CODE_KEY_EXISTS) ++errors; }); Require(winners == 1 && errors == 0 && size(handle) == count / 2 + 1, "TryInsert contention mismatch"); // 删除热点条目,确保其栈上键在销毁容器之前仍有效。 Require(erase(handle, &hotKey, nullptr, nullptr) == FAST_ERROR_CODE_SUCCESS, "Hot key erase failed"); result << (collision ? "collision" : "normal") << ": PASS; keys=1024 threads=4 remaining=512 winner=1\n"; } return result.str(); }
操作或边界应检查的结果
普通散列插入1024 个键,数量和查找一致
全部键同散列仍逐项检查内容
热点 TryInsert四线程恰好一名成功
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 4:43:07

超长音频录音APP大全:长时间记录工具能力盘点

在全日会议、长线访谈、全天研学讲座等场景中&#xff0c;常规录音工具普遍存在长时间录制闪退、大体积音频卡顿、长篇文稿整理繁琐、文件丢失等问题。多数常规工具仅适配短时录音场景&#xff0c;无法支撑数小时乃至全天的长效记录需求。市面主流录音工具中&#xff0c;科会通…

作者头像 李华
网站建设 2026/9/28 4:43:05

安卓手机录音图文总结APP哪个好?工具盘点

安卓端录音类工具的实际使用中&#xff0c;经常会遇到长音频整理耗时、纯文字纪要信息太干、关键现场画面无法和录音绑定的情况&#xff0c;很多用户的核心需求已经从单纯的录清楚声音&#xff0c;转向录音完成后以图文的方式提炼核心信息&#xff0c;生成直观的结构化会议内容…

作者头像 李华
网站建设 2026/9/28 4:43:06

搞活动网站源码踩坑3处,备案不头绪看这篇

搞活动网站源码踩坑3处,备案不头绪看这篇 备案流程一头雾水,看着工信部那几张表就发懵,很多福建做市场的朋友拿到一套 活动网站源码 ,心里直打鼓。别慌,我干了十年建站,见过太多人因为忽略 注意事项 ,导致上线前夜服务器崩了,或者被运营商打回工单。…

作者头像 李华
网站建设 2026/9/28 4:43:03

节后复播前的一次演练,把一个藏了半个月的隐患翻了出来

假期最后一晚十点&#xff0c;朋友的公司群里弹出一条消息&#xff1a;演练通过&#xff0c;但发现一个问题&#xff0c;明天复播前必须修掉。我问他什么问题这么急&#xff0c;他说这事说来话长——一个藏了半个月、三次检查都没发现的隐患&#xff0c;在今晚的全链路演练里现…

作者头像 李华
网站建设 2026/9/28 4:42:36

手机论坛网站模板从零搭建安全避坑指南

手机论坛网站模板从零搭建安全避坑指南 备案流程一头雾水,这是很多中小企业老板在启动手机论坛网站项目时最大的 headache。别急,备案只是开始,真正的风险藏在代码和配置里。今天咱们不聊虚的,直接从 从零搭建…

作者头像 李华