浅谈MatrixOne如何用Go语言设计与实现高性能哈希表

【一月一本技术书】-【Go语言设计与实现】- 9月 用树状的方式表示编程语言的语法结构。每一个节点表示源代码的一个元素。每一颗子树表示一个语法元素。2 * 3 + 7抽象语法树抹去了源代码中不重要的一些字符:空格、分号、括号等接口是计算机系统中多个组件共享的边界。不同的组件能够在边界上交换信息。接口的本质是引入一个新的中间层。调用方可以通过接口与具体的实现分离。解除上下游的耦合。上层的模块不需要依赖下层的具体模块。只需要依赖一个约定好的接口。面向接口的编程方式有着非常强大的生命力。Go语言中的接口是一种内置的类型。定义了一组方法的签名。 阅读详情

目录

MatrixOne数据库是什么?

MatrixOne是一个新一代超融合异构数据库,致力于打造单一架构处理TP、AP、流计算等多种负载的极简大数据引擎。MatrixOne由Go语言所开发,并已于2021年10月开源,目前已经release到0.3版本。在MatrixOne已发布的性能报告中,与业界领先的OLAP数据库Clickhouse相比也不落下风。作为一款Go语言实现的数据库,居然可以与C++实现的顶级OLAP数据库性能媲美,这其中就涉及到了很多方面的优化,包括高性能哈希表的实现,本文就将详细说明MatrixOne是如何用Go实现高性能哈希表的。

Github地址:https://github.com/matrixorigin/matrixone

哈希表数据结构基础

哈希表(Hashtable)是一种非常基础的数据结构,对于数据库的分组聚合和Join查询的性能至关重要。以如下的分组聚合为例(备注,图引自参考文献1):

SELECT col, count(*) FROM table GROUP BY col

groupby

它包含两个处理阶段:第1阶段是使用数据源的数据建立一个哈希表。哈希表中的每条记录都与一个计数器有关。如果记录是新插入的,相关的计数器被设置为1;否则,计数器被递增。第二阶段是将哈希表中的记录集合成一种可用于进一步查询处理的格式。

对于Join查询而言,以如下SQL为例:

SELECT A.left_col, B.right_col FROM A JOIN B USING (key_col)

join

它同样也有两个阶段:第一阶段是使用Join语句右侧表的数据建立一个哈希表,第二阶段是从左侧表中读取数据,并快速探测刚刚建立的哈希表。构建阶段与上面的分组实现类似,但每个哈希表的槽位都存储了对右边列的引用。

由此可见,哈希表对于数据库的SQL基础能力起着很关键的作用 ,本文讨论哈希表的基本设计与对性能的影响,比较各种常见哈希表实现,然后介绍我们为MatrixOne实现的哈希表的设计选择与工程优化,最后是性能测试结果。

我们预设读者已经对文中提到哈希表相关的概念有所了解,主要讨论其对性能的影响,不做详细科普。如果对基本概念并不了解,请从其他来源获取相关知识,例如维基百科。

哈希表基本设计与对性能的影响

碰撞处理

不同的key经哈希函数映射到同一个桶,称作哈希碰撞。各种实现中最常见的碰撞处理机制是链地址法(chaining)和开放寻址法(open-addressing)。

链地址法

在哈希表中,每个桶存储一个链表,把相同哈希值的不同元素放在链表中。这是C++标准容器通常采用的方式。

优点:

  • 实现最简单直观
  • 空间浪费较少

开放寻址法

若插入时发生碰撞,从碰撞发生的那个哈希桶开始,按照一定的次序,找出一个空闲的桶。

优点:

  • 每次插入或查找操作只有一次指针跳转,对CPU缓存更友好
  • 所有数据存放在一块连续内存中,内存碎片更少

当max load factor较大时,性能不如链地址法。然而当我们主动牺牲内存,选择较小的max load factor时(例如0.5),形势就发生逆转,开放寻址法反而性能更好。因为这时哈希碰撞的概率大大减小,缓存友好的优势得以凸显。

值得注意的是,C++标准容器实现不采用开放寻址法是由C++标准决定,而非根据性能考量(详细可见这个boost文档)。

Max load factor

对链地址法哈希表,指平均每个桶所含元素个数上限。

对开放寻址法哈希表,指已填充的桶个数占总的桶个数的最大比值。

max load factor越小,哈希碰撞的概率越小,同时浪费的空间也越多。

Growth factor

指当已填充的桶达到max load factor限定的上限,哈希表需要rehash时,内存扩张的倍数。growth factor越大,哈希表rehash的次数越少,但是内存浪费越多。

空闲桶探测方法

在开放寻址法中,若哈希函数返回的桶已经被其他key占据,需要通过预设规则去临近的桶中寻找空闲桶。最常见有以下方法(假设一共|T|个桶,哈希函数为H(k)):

  • 线性探测(linear probing):对i = 0, 1, 2…,依次探测第H(k, i) = H(k) + ci mod |T|个桶。
  • 平方探测(quadratic probing):对i = 0, 1, 2…,依次探测H(k, i) = H(k) + c1i + c2i2 mod |T|。其中c2不能为0,否则退化成线性探测。
  • 双重哈希(double hashing):使用两个不同哈希函数,依次探测H(k, i) = (H1(k) + i * H2(k)) mod |T|。

线性探测法对比其他方法,平均需要探测的桶数量最多。但是线性探测法访问内存总是顺序连续访问,最为缓存友好。因此,在冲突概率不大的时候(max load factor较小),线性探测法是最快的方式。

其他还有一些更精巧的探测方法,例如cuckoo hashing,hopscotch hashing,robin hood hashing(文章开头给的维基百科页面里都有介绍)。然而它们都是为max load factor较大(0.6以上)的情形设计的。在max load factor = 0.5的时候,实际测试中性能都不如最原始最直接的线性探测。

一些常见的哈希表实现

C++ std::unordered_map/boost::unordered_map

基于上面提到的原因,处理碰撞使用链地址法。默认max load factor = 1,growth factor = 2。设计简单,不用多说。

go map

通过阅读golang库的代码得知,golang内置的map采用链地址法。

swisstable

来自于Google推出的abseil库,是一款性能十分优秀的针对通用场景的哈希表实现。碰撞处理方式使用开放寻址,地址探测方法是在分块内部做平方探测。parallel-hashmap,以及rust语言标准库的哈希表实现,都是基于swisstable。更多信息可参考此处。

ClickHouse的哈希表实现

采用开放寻址,线性探测。max load factor为0.5,growth factor在桶数量小于2^24时为4,否则为2。

针对key为字符串的情形,ClickHouse还有专门的根据字符串长度自适应的哈希表实现,具体参见论文,这里不展开。

高效哈希表的设计与实现

MatrixOne是使用go语言开发的数据库,市面上的知名哈希表实现我们都无缘直接使用,而在初始的实现中,我们采用了go语言自带的map,结果高基数的分组(比如多属性分组很容易做到高基数)性能相比ClickHouse差距会接近一个数量级,低基数也慢不少,所以我们必须实现自己的版本。

基本设计与参数选择

ClickHouse的哈希表在自带的benchmark中表现出了最高的性能,因此借鉴其具体实现成为十分自然的选择。我们照搬了ClickHouse的如下设计:

  • 开放寻址
  • 线性探测
  • max load factor = 0.5,growth factor = 4
  • 整数哈希函数基于CRC32指令

具体原因前面已经提到,当max load factor不大时,开放寻址法要优于链地制法,同时线性探测法又优于其他的探测方法。

并做了如下修改(优化):

  • 字符串哈希函数基于AESENC指令
  • 插入、查找、扩张时批量计算哈希函数
  • 扩张时直接遍历旧表插入新表
    • ClickHouse是先把旧表整体memcpy到新表中,再遍历调整位置。没找到如此设计的原因,但是经测试性能不如我们的方式。

哈希函数

哈希函数的作用是将任意的key映射到哈希表的一个地址,是哈希表插入和查找过程的第一步。数据库场景中使用的哈希函数,应该满足:

  • 速度尽量快
  • 打散得尽量均匀(避免聚集),这样使得碰撞概率尽量小,若哈希表做分区的话也可保证分得均匀
  • 不需要考虑密码学安全性

在ClickHouse的实现中,主要使用现代CPU(amd64或者arm64)自带的CRC32指令来实现哈希函数。

inline DB::UInt64 intHashCRC32(DB::UInt64 x)
{
#ifdef __SSE4_2__
	return _mm_crc32_u64(-1ULL, x);
#elif defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
	return __crc32cd(-1U, x);
#else
    /// On other platforms we do not have CRC32. NOTE This can be confusing.
	return intHash64(x);
#endif
}

经实测,打散效果非常不错,而且每个64位整数只需一条CPU指令,已经达到理论极限,速度远超xxhash, Murmur3等一系列没有使用特殊指令的“普通”哈希函数。

我们的整数哈希函数也使用同样的方法实现。

TEXT ·Crc32Int64Hash(SB), NOSPLIT, $0-16
	MOVQ   $-1, SI
	CRC32Q data+0(FP), SI
	MOVQ   SI, ret+8(FP)

	RET

值得注意的是,go语言不具有C/C++/rust的intrinsics函数库,因此要使用某些特殊的指令,只能用go汇编自己实现。而且go汇编函数目前无法内联,因此为了最大化性能,需要把计算哈希函数的过程做成批量化。这点将在后续的文章中具体介绍。

包含CRC32指令的SSE4.2最早见于2008年发布的Nehalem架构CPU。因此我们假设用户的CPU都支持这一指令,毕竟更老的设备用来跑AP数据库似乎不太合适了。

对于字符串类型的哈希函数,ClickHouse仍然通过CRC32指令实现。我们经过调研,选择基于AESENC指令来实现。AESENC包含在AES-NI指令集中,由Intel于2010年发布的Westmere架构中首次引入,单条指令执行AES加密过程中的一个round。AESENC平均一条指令处理128位数据,比CRC32更快,而且提供128位结果,适应更多应用场景(对比CRC32只有32位)。在实测中基于AESENC的哈希函数打散效果同样优秀。网络上基于AESENC指令实现的哈希函数已经有不少,例如nabhash,meowhash,aHash。我们自己的实现在这里(amd64)和这里(arm64)。

特殊优化

我们针对字符串key,使用了一种非常规的设计:不在哈希表中保存原始的key,而是存两个不同的基于AESENC指令的哈希函数,其中一个64位的结果当作哈希值,另一个128位的结果当作“key”。192位再加上64位的value,每个桶宽度正好是32字节,可完全与CPU的cacheline对齐。在碰撞处理中,不比较原始key,而是比较这192位的数据。不同的字符串两个哈希值同时碰撞的概率极低,在AP系统中可以忽略不计。这样做的优势是把变长字符串比较变成了定长的3个64位整数比较,而且还省掉一次指针跳转开销,大大加速碰撞检测的过程。

代码片段:

type StringHashMapCell struct {
	HashState [3]uint64
	Mapped    uint64
}

...

func (ht *StringHashMap) findCell(state *[3]uint64) *StringHashMapCell {
	mask := ht.cellCnt - 1
	idx := state[0] & mask
	for {
		cell := &ht.cells[idx]
		if cell.Mapped == 0 || cell.HashState == *state {
			return cell
		}
		idx = (idx + 1) & mask
	}
	return nil
}

具体实现代码

  • https://github.com/matrixorigin/matrixone/tree/main/pkg/container/hashtable

性能测试

测试环境

  • CPU:AMD Ryzen 9 5900X
  • 内存:DDR4-3200 32GB
  • 操作系统:Manjaro 21.2
  • 内核版本:5.16.11
  • 数据:ClickHouse提供的一亿行Yandex.Metrica数据集

测试内容

每个测试都是顺序插入一亿条记录,再以相同顺序查找一亿条记录。过程类似如下代码所展示:

...
// Insert
for (auto k : data) {
	hash_map.emplace(k, hash_map.size() + 1);
}
...
// Find
size_t sum = 0;
for (auto k : data) {
	sum += hash_map[k]
}
...

整数key结果

下表中记录了一些哈希表实现对Yandex.Metrica数据集不同属性insert/find所用的时间,单位毫秒(ms)。

属性ParamPriceCounterIDRegionIDFUniqIDUserIDURLHashRefererHashWatchID
基数1109650690401511266817630976207148652159875699997493
ClickHouse HashMap67 / 46175 / 147154 / 1411235 / 8731651 / 8932051 / 10271945 / 10335389 / 2040
google::dense_hash_map767 / 758273 / 262261 / 2601861 / 10711909 / 10202134 / 11582203 / 11566181 / 2365
absl::flat_hash_map227 / 223236 / 230230 / 2311544 / 12631685 / 13542092 / 15041987 / 15216278 / 3166
std::unordered_map298 / 301323 / 356443 / 4434740 / 22774966 / 24595473 / 30585536 / 284924832 / 6348
tsl::hopscotch_map166 / 162376 / 250167 / 1672151 / 9202225 / 10063055 / 12782830 / 12469473 / 3170
tsl::robin_map247 / 281240 / 225276 / 2541641 / 11522052 / 11322445 / 13202371 / 12957409 / 2651
tsl::sparse_map425 / 405550 / 419441 / 4153090 / 19063773 / 22324712 / 27604508 / 260518342 / 7025
go map361 / 433537 / 482461 / 4603039 / 17123186 / 18184527 / 25714175 / 241115774 / 6027
MatrixOne Int64HashMap190 / 182190 / 191191 / 1911112 / 7591160 / 7931445 / 9071400 / 9223205 / 1613

可以看出当基数非常小的时候,ClickHouse实现最快。在基数较大时,MatrixOrigin的实现最快,且基数越大领先得越多。

字符串key结果

属性OriginalURLTitleURLReferer
基数851012394257181834203519720815
ClickHouse StringHashMap2840 / 16853873 / 28445726 / 37134751 / 2987
ClickHouse HashMapWithSavedHash2628 / 17083508 / 29055332 / 36794458 / 2963
ClickHouse HashMap3931 / 15704203 / 25737137 / 32826159 / 2644
go map5402 / 24409515 / 456412881 / 574110750 / 4624
MatrixOne StringHashMap1743 / 12282434 / 18292520 / 18112563 / 1955

结果与整数key类似,基数越大我们的实现领先越多。

总结

以上性能测试结果已经大大超出了我们最初的预期。我们从移植ClickHouse自带哈希表出发,预计由于语言差异,最终能达到C++原版70~80%的性能。随着反复的迭代优化,以及不断尝试改变ClickHouse原本的一些设计,最终在哈希表的插入和查找性能上竟然超越了C++版本。

这说明哪怕是一些非常基础的通常被认为早已研究透了的数据结构,通过针对特定应用场景仔细的设计和部分使用汇编加速,也可让go实现的版本在性能上一点不输C/C++/rust版本。这也为我们坚持用go语言开发高性能数据库提供了更多信心。

参考文献

  1. Tianqi Zheng, Zhibin Zhang, and Xueqi Cheng. 2020. SAHA: A String Adaptive Hash Table for Analytical Databases. Applied Sciences 10, 6 (2020). https: //doi.org/10.3390/app10061915

欢迎加入MatrixOne社区

官网:matrixorigin.cn
源码:github.com/matrixorigin/matrixone
Slack:matrixoneworkspace.slack.com
知乎 | 优快云 | 墨天轮 | OSCHINA | InfoQ:MatrixOrigin

一文告诉你:如何在trae中编译运行GD32程序,并让AI帮你修改代码 本文详细介绍了如何将GD32程序如何用官方固件库构建出来,然后从Keil迁移到国产免费工具Trae,并利用AI进行代码修改的全过程。 阅读详情

相关推荐

txt经纬度批量转面要素(附自定义ArcGIS工具箱方法)

当涉及大量txt坐标文件需要转换成面要素的时候,逐步操作工作量较大。本文由需求出发,以ArcGIS10.2为例,采用python脚本自定义ArcGIS工具,实现批量操作的目的。

m0_59216200的博客 1820

2022-08-18 多线程安全的Parallel Hashmap

记录多线程安全的并行hash map。

悟世之路 2932

bcftools实战指南:从VCF文件处理到变异分析全流程解析

在基因组数据分析中,VCF(Variant Call Format)文件是存储基因序列变异信息的标准格式,广泛应用于群体遗传学和生物信息学研究。其核心原理是通过结构化文本记录SNP、INDEL等变异位点的基因型、质量值和注释信息。掌握高效处理VCF文件的技术,对于提升变异检测、数据清洗和下游分析的工作流效率具有重要价值。在生物信息学工具生态中,bcftools作为处理VCF/BCF文件的瑞士军刀,通过模块化设计实现了数据查询、过滤、统计和格式转换等核心功能。其流式处理架构支持管道化操作,能有效应对海量基因组

weixin_29081703的博客 324

Matrix Go 客户端库使用指南

Matrix Go 客户端库使用指南 项目介绍 Matrix Go (gomatrix) 是 Matrix 协议的一个 Go 语言实现客户端库。Matrix 是一个开放源代码的通信协议,旨在创建一个去中心化的即时通讯网络。通过 gomatrix,开发者能够轻松地在他们的Go应用程序中集成Matrix功能,实现点对点、群组聊天、音视频通话以及端到端加密等功能。此项目由 Matrix 组织维护,支持...

gitblog_00120的博客 773

DLMS—Cryptographic algorithms—(Green-Book)加密算法

密码学是数学的一个分支,基于数据的转换,并且可以用来提供多种安全服务:保密性、数据完整性、认证、授权和不可否认性。密码学依赖于两个基本组成部分:算法(或密码学方法)和密钥。算法是一个数学函数,而密钥是在转换过程中使用的参数。密码算法和密钥用于对数据应用密码保护(例如,加密数据或生成数字签名),以及移除或检查保护(例如,解密加密的数据或验证数字签名)。密码哈希函数:这类函数不需要密钥(尽管它们可以以使用密钥的模式使用)。哈希函数通常用作算法的一个组成部分,以提供安全服务。见9.2.3.2节。对称密钥算法。

一个bug是bug,多个bug能work 1711

SST专题(2-5)MMC-SST 输入级的环流抑制

本文研究了模块化多电平换流器(MMC)的数学模型及其环流抑制控制方法。首先建立了MMC等效电路模型,推导了桥臂电流方程和虚拟电动势表达式,提出通过控制桥臂电压修正量来调节内部电流而不影响外部特性。针对MMC特有的二倍频负序环流问题,设计了基于负序旋转坐标变换的环流抑制控制器(CCSC),将时变环流转换为直流量进行控制。通过比例-积分调节和电压前馈补偿,生成内部不平衡压降参考值,最终形成包含功率控制和环流抑制的整体控制结构。仿真结果表明该方法能有效抑制内部环流,同时保持系统稳定运行。

嵌入式老牛的博客 539

Go 语言设计与实现

第一部分 预备知识 第一章 准备工作 1.1 调试 Go 语言 第二章 编译原理 目录 第一部分 预备知识 第一章 准备工作 1.1 调试 Go 语言 第二章 编译原理 2.1 概述 2.2 词法和语法分析 2.3 类型检查 2.4 中间代码生成 2.5 机器码生成 2.1 概述 2.2 词法和语法分析 2.3 类型检查 2.4 中间代码生成 2.5 机器码生成 ...

D_Guco的专栏 5511

手把手教你学Simulink--基于新型通信技术集成的场景实例:无人机利用激光通信实现高速率数据传输

摘要: 本文基于Simulink搭建无人机激光通信仿真系统,解决传统射频通信带宽不足问题。系统通过五层架构(发射机、信道、PAT系统、接收机、性能分析)实现Gbps级高速传输,重点建模大气衰减(雾/雨)、光束发散、PAT精跟踪(Stateflow+PID控制)等核心模块。仿真结果显示:晴天链路可达2.5Gbps(BER 1e-8),浓雾下链路中断,验证了雾是主要性能限制因素。案例涵盖调制方式选择、动态环境仿真及3D可视化,为无人机高速数据传输提供可扩展的仿真框架,并指出混合FSO/RF、AI-PAT等优化方

MHD0815的博客 181

Matrix Go 客户端库指南

Matrix Go 客户端库指南 1. 项目目录结构及介绍 Matrix Go 库(gomatrix)旨在提供一个简单易用的Go语言接口来交互Matrix协议。下面是其主要的目录结构和组件简介: gomatrix/ ├── cmd/ # 包含示例程序或简单的命令行工具。 ├── matrix-client/ # 核心库代码,实现与Matrix服务的交互...

gitblog_00672的博客 493

点云焊缝提取

本文介绍了一个基于PCL库的点云处理流程,包含三个核心模块:MLS平滑处理通过多项式拟合修正点云位置;差异提取通过双向匹配定位源/目标点云的非重叠区域;统计过滤剔除离群噪声点。该流程采用"平滑-筛选-净化"的通用思路,将复杂算法封装为可配置接口,实现了工业级点云预处理。文章重点分析了各模块的原理、PCL接口调用及参数设计逻辑,同时指出参数调优、算法扩展等深入探索方向,展现了PCL在点云处理中的模块化优势与实用价值。

weixin_45196569的博客 251

Vue3 - 实现集成配置百度语音识别转文字,长按或开启录音并将录音文件实时转换为文字,上传音频文件利用百度语音识别API转换为文本并展示(vue3百度智能云API实现上传录音文件并转换成文字案例)

vue3对接百度智能云语音识别,vue3 h5移动端网页中实现语音识别,百度语音识别录音转文字_百度智能云,vue3如何使用百度语音识别,如何将语音转文字,使用vue3实现录音并将录音转换为文字,vue3如何实现语音输入功能功能,vue3集成百度智能云API实现录音转文字详细教程完整示例代码demo,VUE3使用百度语音识别语音转文字,vue调用百度语音识别,vue3百度语音识别文字并展示功能,vue3免费语音转文本api,百度语音识别申请配置教程,Vue3项目配置自定义界面百度语音识别转文字和原生使用方式

🏆 前端领域优质创作者 2730

浅谈 Go 语言高性能哈希表的设计与实现

目录1. MatrixOne数据库是什么?2. 哈希表数据结构基础3. 哈希表基本设计与对性能的影响3.1 链地址法3.2 开放寻址法3.3 碰撞处理3.4 Max load factor3.5 Growth factor3.6 空闲桶探测方法4. 一些常见的哈希表实现4.1C++4.2std::unord...

Go中国 1469

innovus:sroute 双层follow pin的做法

根据std cellpower pin的层次可以分成两种情况。

m0_61544122的博客 2733

哈希知识点

最好的查询是,进行很少的比较次数就能够将元素找到,因此在C++11中,STL又提供了4个unordered系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是其底层结构不同,本文中只对unordered_map和unordered_set进行介绍,unordered_multimap和unordered_multiset可查看文档介绍。注意:布隆过滤器如果说某个元素不存在时,该元素一定不存在,如果该元素存在时,该元素可能存在,因为有些哈希函数存在一定的误判。

2021wuwei 444

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

澳鹏MatrixGo自定义模板:重塑数据标注的敏捷范式

数据标注行业正经历从标准化向场景化转型。澳鹏MatrixGo平台推出的自定义模板功能,通过四大创新突破行业瓶颈:1)可视化拖拽界面实现零代码工具搭建;2)智能规则配置简化复杂任务处理;3)全链路质检体系确保数据质量闭环;4)专业组件库覆盖文本、代码、多媒体等八大应用场景(包括质量评分、信息提取、视频理解等)。该升级使标注工具开发摆脱编码限制,让业务专家能快速创建专业标注界面,显著提升大模型训练数据的生产效率和质量。

Appen_China的博客 946

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

哈希表解密:性能优化与实践策略

1.背景介绍 哈希表(Hash Table)是一种常用的数据结构,它通过将关键字映射到其他数据类型(通常是数组),提供了高效的查找、插入和删除操作。哈希表在计算机科学和软件工程中具有广泛的应用,例如数据库、缓存、算法等。在这篇文章中,我们将深入探讨哈希表的性能优化和实践策略,以帮助您更好地理解和应用这一重要的数据结构。 2.核心概念与联系 在了解哈希表的性能优化和实践策略之前,我们首先需要了...

AI天才研究院 1677

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

SwissTable:高性能哈希表实现

你好,我是俞凡,在Motorola做过研发,现在在Mavenir做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。查找时,先计算键的哈希值,然后确定相应的桶,并检查桶内每个插槽。

残星说梦话 2003

Redis源码学习:高性能Hash表的设计与实现

哈希表是一种通过哈希函数将键映射到值的数据结构。简单来说,就是通过一个计算公式(哈希函数)把一个键(比如一个名字)转换成一个数组的索引,数组中的每一个元素就是一个哈希桶(也叫bucket),然后在这个索引位置存储对应的值(比如电话号码)。这样我们就能以O(1)的时间复杂度通过键快速找到对应的值。通过链式哈希,Redis有效地解决了哈希冲突的问题;通过渐进式rehash,Redis确保了哈希表扩展时的高效性和稳定性。这些机制让Redis哈希表在处理大量数据时仍然保持高效。

DL Forge 1844

从零构建高性能哈希表,C语言链地址法实现全攻略

掌握哈希表底层原理,高效解决冲突问题。本文详解C语言实现简单哈希表(链地址法),涵盖插入、查找、删除操作,适用于数据存储与检索场景,结构清晰、易于扩展,是学习高性能哈希表实现的实用指南,值得收藏。

PixelWander的博客 592

基于现代C++特性的高性能哈希表设计原理

实验数据显示,当元素数量超过10时,现代C++哈希表(如std::unordered_map)的查找速度可达红黑树的3-5倍。哈希表作为以空间换时间的经典数据结构,在现代C++中通过语言特性和算法优化实现了质的飞跃。其核心价值在于将键值对的存储与查找复杂度从O(n)降至平均O(1),这种效率跃迁使其成为数据库索引、缓存系统等场景的基石。模板元编程:通过std::hash特化实现类型安全的哈希函数,避免传统C风格的强制类型转换风险。自定义哈希函数:针对特定数据类型(如UUID)设计专用哈希函数,降低碰撞率。

a20215的博客 969

标注平台工作流:如何提高训练数据质量与管理效率

工作流是一组相互关联的任务,可帮助简化和实现复杂流程自动化。在AI数据标注的背景下,工作流可被视为指导数据从采集到最终交付的一系列步骤。工作流可包括数据采集、数据标注、质量控制和数据交付等任务。工作流的每一步都旨在确保数据的准确性、一致性和高质量。工作流按逻辑顺序连接这些任务,可以提高标注过程的效率和可扩展性,减少标注大量数据所需的时间和精力。工作流是管理许多AI应用(包括LLM)所需的复杂数据标注过程的一个重要工具。

Appen_China的博客 1406

互联网高科技公司领导AI工业化,MatrixGo加速人工智能落地

澳鹏中国高级产研总监张童皓表示,2022年将是AI标注数据供给产业的一个分水岭——之前的AI标注数据行业最佳实践逐渐沉淀为可复用的软件工具,以更为自动化、标准化和规模化可扩展的方式,为整个AI模型生命周期提供高精度和高质量的标注数据,满足数据采集、标注、数据版本更新、AI模型再训练等端到端过程,以工业化方式构建起完整AI标注数据供应链。对于专业的AI标注数据服务公司来说,将已有的方法论进行沉淀,再将行之有效的方式固化下来,形成能够复用且易用的产品级能力,就能大规模赋能AI模型迭代。

Appen_China的博客 1764

Go语言设计与实现 -- 栈空间管理

Go 语言的汇编代码包含 BP 和 SP 两个栈寄存器,它们分别存储了栈的基址指针和栈顶的地址,栈内存与函数调用的关系非常紧密,我们在函数调用一节中曾经介绍过栈区,BP 和 SP 之间的内存就是当前函数的调用栈。

qq_61039408的博客 806

Go语言设计与实现 学习笔记 第二章 编译原理

早期的CPU为了减少机器语言指令的数量使用复杂指令集完成计算任务,这两者其实并没有绝对的好坏,它们只是在一些设计上的选择不同以达到不同的目的,我们会在后面的机器码生成一节中详细介绍指令集架构,不过各位读者也可以主动了解相关的内容。所有的编译过程其实都是从解析代码的源文件开始的,词法分析的作用就是解析源代码文件,它将文件中的字符串序列转换成Token序列,方便后面的处理和解析,我们一般会把执行词法分析的程序称为词法解析器(lexer)。

tus00000的博客 1585

Go语言设计与实现 -- 上下文

我们先来看一下DeadlineDoneChannelChannelContextValueValuekey。

qq_61039408的博客 849

Go语言设计与实现

文章目录选读这本书的理由内容编译原理 思考一个问题:***是什么,为什么会有它,什么历史场景,它是怎么设计的,为什么这么决策 选读这本书的理由 我非常喜欢作者通过历史的演进和社区讨论理解设计背后的决策和原因 从编译层次理解Go语言设计 内容 理解编译器的 词法与语法解析、类型检查、中间代码生成以及机器码生成过程; 理解 数组、切片、哈希表和字符串等数据结构的内部表示以及常见操作的原理; 理解...

cugbtang 3007
上一篇: 茴字有四种写法,HTAP呢?
下一篇: Push还是Pull,这是个问题么?
MatrixOrigin
博客等级 码龄5年 708粉丝 230原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值