ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

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

〖共创稿事节〗HarmonyOS 7 新特性实战(13):在模拟器验证 FAST 四线程索引与热点插入 先跑通一轮有确定答案的实验import{runFastExperiment}fromlibspatial_audio.so;// 在页面异步操作中等待结果避免阻塞 UI 线程。constresult:stringawaitrunFastExperiment(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-AL80API 26通过相同页面入口连续运行两次。每次均回读 normal: PASS 与 collision: PASS1024 个键、4 个线程删除后 remaining512热点插入 winner1。页面端到端耗时分别为 39 ms、34 ms。这些结果覆盖固定键集的插入、查找、更新、删除和热点争抢。两次运行没有控制温度、频率或系统负载也没有对照容器故不据此推导吞吐量或加速比。截图底部仍保留旧版关于模拟器性能的通用提示采集设备为上述真机。补一次前台重复执行先确认固定用例不会偶发失效2026-09-18 在可见的 API 26 模拟器ArticleLabAPI26Fresh中连续触发同一个页面入口 5 次。每次都走完普通散列、全部键碰撞和热点TryInsert三部分布局快照均记录normal: PASS、collision: PASS与winner1。端到端耗时依次为 258、154、94、97、125 ms范围为 94–258 ms。这组复跑证据可在 配套汇总记录 与同名前缀的 5 份布局快照中复查。它只覆盖固定的 1024 键、4 线程有限任务且端到端时间包含 ArkTS 调用和任务调度现有证据只支持“固定正确性用例连续通过”不支持报告吞吐量、延迟百分位或比较 FAST 与受锁普通容器的性能。2026-09-23 在 HBN-AL80API 26再运行一次当前包普通散列与全碰撞都回读 PASS均为keys1024、threads4、remaining512、winner1页面端到端为 38 ms。该单次结果只确认固定正确性集没有在当前真机上偶发失败不用于性能比较。让容器先释放再回收数据FAST 只保存键值指针数据所有权仍在调用者。Demo 先为整轮数据分配定长数组再创建容器插入后不调整数组大小。Native 异步任务内部启动线程所有线程 join 后再销毁容器最后释放数组。更新前后的值都保留到实验结束避免另一线程读到失效内存。std::vectoruint64_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_ptrvoid, decltype(destroy) guard(handle, destroy);页面离开后不再更新页面状态后台任务继续完成这组有限工作并释放容器这里没有强行终止持锁线程。模块限制同一时间只能执行一个 FAST 实验连续点击不会堆积无限任务。后续扩大实验时保留的约束展品资源扫描、图片解码和页面查询同时发生时多个线程可能争用同一份索引。把普通容器换成并发容器看起来直接但如果键和值的生命周期没有理清读得更快也可能读到已经释放的数据。FAST Kit 提供并发哈希表 Native 能力。本地头文件fast_ads_concurrent_hashmap.h的基础接口起始版本为 6.1.1API 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.Getdecltype(HMS_FAST_ConcurrentHashmap_Create)(HMS_FAST_ConcurrentHashmap_Create); auto destroy library.Getdecltype(HMS_FAST_ConcurrentHashmap_Destroy)(HMS_FAST_ConcurrentHashmap_Destroy); auto insert library.Getdecltype(HMS_FAST_ConcurrentHashmap_Insert)(HMS_FAST_ConcurrentHashmap_Insert); auto find library.Getdecltype(HMS_FAST_ConcurrentHashmap_Find)(HMS_FAST_ConcurrentHashmap_Find); auto erase library.Getdecltype(HMS_FAST_ConcurrentHashmap_Erase)(HMS_FAST_ConcurrentHashmap_Erase); auto size library.Getdecltype(HMS_FAST_ConcurrentHashmap_Size)(HMS_FAST_ConcurrentHashmap_Size); auto tryInsert library.Getdecltype(HMS_FAST_ConcurrentHashmap_TryInsert)(HMS_FAST_ConcurrentHashmap_TryInsert); std::ostringstream result; for (bool collision : {false, true}) { constexpr size_t count 1024; // 指针存入容器后不再调整数组大小线程退出并销毁容器后才释放数组。 std::vectoruint64_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_ptrvoid, decltype(destroy) guard(handle, destroy); std::atomicsize_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::atomicsize_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; keys1024 threads4 remaining512 winner1\n; } return result.str(); }操作或边界应检查的结果普通散列插入1024 个键数量和查找一致全部键同散列仍逐项检查内容热点 TryInsert四线程恰好一名成功
返回列表