padmux引脚复用

对于sstar芯片。

pad mux dtsi文件路径为kernel/arch/arm/boot/dts/xxx-padmux.dtsi。根据项目需求,修改该文件即可设置pin脚的复用模式。

image-20240808142459883

第一列为pin脚名称,第二列为pin脚复用模式,参考m_stPadMuxTbl 数组中的mode选项,第三列为复用功能中具体的pin脚作用,参考mdrv_puse.h

gpio映射表

每一个chip都有一个gpio-mapping-table.xlx文件,里面有相关gpio设置。

padmux表

每个pin脚具体的复用功能也可以见mhal_pinmux.c的m_stPadMuxTbl数组。复用关系优先级从高到低,gpio功能的优先级最低。复用某个pin脚的某个功能前要确认高优先级复用是关闭的。

image-20240808142923826

1
2
3
4
5
6
PAD_FUART_TX:        引脚
CHIPTOP_BANK: 寄存器地址
REG_SR_PCK_MODE: 偏移地址
REG_PWM0_MODE_MASK mask位
BIT1|BIT0 对应的设置bit位
PINMUX_FOR_PWM0_MODE_3: 模式
设置gpio9为gpio模式

image-20240808143130176

通过读取寄存器来确认复用是否成功

设置i2cs0为pwm模式

image-20240808143231127

image-20240808143325826

标准spi,双线,三线,四线spi

标准spi

CLK,CS,MOSI,MISO,WP,Hold。在标准spi下,spi是全双工的,MOSI,MISO分别负责不同方向的传输。大多数单个SPI串行吞吐速率达到10Mbps左右。

双线spi

CLK,CS,IO0,IO1,WP,Hold,双线spi是Dual SPI就是MOSI,MISO同时朝一个方向发数据,单词可以同时传输2bit,此时MOSI 和 MISO则被改称为IO0和IO1。在双线spi下,spi是双线半双工。串行吞吐量速率达到20Mbps左右。

三线spi

SCLK, MOSI,CS。数据收发只有一根线,适用于单工通讯,主机只发送或者只接收从机的数据。spi是半双工的。

四线spi

CLK,CS,IO0,IO1,IO2,IO3,Wp,Hold。Quad Spi,IO0,IO1,IO2,IO3被用于同一个方向传输数据。单次可传输4bit。此时MOSI和MISO为IO0,IO1,而WP,HOLD被用作IO2,IO3,CS和CLK不变。半双工40Mbps

emmc分区

emmc有默认四个物理分区。是出场即默认存在的。

image-20240807190154285

各个分区有独立的地址,都是从0x00开始的。Boot1,Boot2和RPMB的大小会在出厂的时候就设定好。两个boot的大小是完全一致的。由Extended CSD register的BOOT_SIZE_MULT Filed决定。大小的计算公式如下:

image-20240807191047225

一般情况下,Boot Area Partition 的大小都为 4 MB,即 BOOT_SIZE_MULT 为 32,部分芯片厂家会提供改写 BOOT_SIZE_MULT 的功能来改变 Boot Area Partition 的容量大小。BOOT_SIZE_MULT 最大可以为 255,即 Boot Area Partition 的最大容量大小可以为 255 x 128 KB = 32640 KB = 31.875 MB。

分区编制

具体的数据读写访问操作实际访问哪一个硬件分区。是由EMMC 的 Extended CSC register的PARTITION_CONFIG Field 中 的 Bit[2:0]: PARTITION_ACCESS 决定的,用户可以通过配置来切换硬件分区的访问。

也就是说,用户在访问特定的分区前,需要先发送命令,配置 PARTITION_ACCESS,然后再发送相关的数据访问请求。

从Boot area启动

eMMC 中定义了 Boot State,在 Power-up、HW reset 或者 SW reset 后,如果满足一定的条件,eMMC 就会进入该 State。进入 Boot State 的条件如下:

Original Boot Operation
CMD 信号保持低电平不少于 74 个时钟周期,会触发 Original Boot Operation,进入 Boot State。

Alternative Boot Operation
在 74 个时钟周期后,在 CMD 信号首次拉低或者 Host 发送 CMD1 之前,Host 发送参数为 0xFFFFFFFA 的 COM0时,会触发 Alternative Boot Operation,进入 Boot State。

在 Boot State 下,如果有配置 BOOT_ACK,eMMC 会先发送 “010” 的 ACK 包,接着 eMMC 会将最大为 128Kbytes x BOOT_SIZE_MULT 的 Boot Data 发送给 Host。传输过程中,Host 可以通过拉高 CMD 信号 (Original Boot 中),或者发送 Reset 命令 (Alternative Boot 中) 来中断 eMMC 的数据发送,完成 Boot Data 传输。

Boot Data 根据 Extended CSD register 的 PARTITION_CONFIG Field 的 Bit[5:3]:BOOT_PARTITION_ENABLE 的设定,可以从 Boot Area Partition 1、Boot Area Partition 2 或者 User Data Area 读出。

Boot Data 存储在 Boot Area 比在 User Data Area 中要更加的安全,可以减少意外修改导致系统无法启动,同时无法更新系统的情况出现。

http://www.wowotech.net/basic_tech/emmc_partitions.html

RPMB Partition

Replay Protected Memory Block Partition是emmc中一个具有安全特性的分区。eMMC 在写入数据到 RPMB 时,会校验数据的合法性,只有指定的 Host 才能够写入,同时在读数据时,也提供了签名机制,保证 Host 读取到的数据是 RPMB 内部数据,而不是攻击者伪造的数据。

RPMB 在实际应用中,通常用于存储一些有防止非法篡改需求的数据,例如手机上指纹支付相关的公钥、序列号等。RPMB 可以对写入操作进行鉴权,但是读取并不需要鉴权,任何人都可以进行读取的操作,因此存储到 RPMB 的数据通常会进行加密后再存储。

容量大小

两个 RPMB Partition 的大小是由 Extended CSD register 的 BOOT_SIZE_MULT Field 决定,大小的计算公式如下:

Size = 128Kbytes x BOOT_SIZE_MULT

一般情况下,Boot Area Partition 的大小为 4 MB,即 RPMB_SIZE_MULT 为 32,部分芯片厂家会提供改写 RPMB_SIZE_MULT 的功能来改变 RPMB Partition 的容量大小。RPMB_SIZE_MULT 最大可以为 128,即 Boot Area Partition 的最大容量大小可以为 128 x 128 KB = 16384 KB = 16 MB。

Replay Protected 原理

使用 eMMC 的产品,在产线生产时,会为每一个产品生产一个唯一的 256 bits 的 Secure Key,烧写到 eMMC 的 OTP 区域(只能烧写一次的区域),同时 Host 在安全区域中(例如:TEE)也会保留该 Secure Key。

在 eMMC 内部,还有一个RPMB Write Counter。RPMB 每进行一次合法的写入操作时,Write Counter 就会自动加一 。

通过 Secure Key 和 Write Counter 的应用,RMPB 可以实现数据读取和写入的 Replay Protect。

User Data Area

通常是EMMC分区中最大的一个。在实际产品中共,是主要区域。

容量大小

容量大小不需要设置,在配置完其他区域之后,扣除Enhanced attribute损耗的容量,剩余的就是UDA的容量。

区域属性

eMMC 标准中,支持为 UDA 中一个特定大小的区域设定 Enhanced attribute。与 GPP 中的 Enhanced attribute 相同,eMMC 标准也没有定义该区域设定 Enhanced attribute 后对 eMMC 的影响。Enhanced attribute 的具体作用,由芯片制造商定义、

  • Default, 未设定 Enhanced attribute。
  • Enhanced storage media, 设定该区域为 Enhanced storage media。

在实际的产品中,UDA 区域设定为 Enhanced storage media 后,一般是把该区域的存储介质从 MLC 改变为 SLC。通常,产品中可以将某一个 SW Partition 设定为 Enhanced storage media,以获得更好的性能和健壮性。

命令说明

mmc dev [dev] [part]

切换物理分区。mmc 设备编号,第一个为 0 part: 0 表示不访问引导分区 1 表示访问引导分区 1(boot0) 2 表示访问引导分区 2(boot1)

eg:切换到引导分区 1 –> mmc dev 0 1

mmc bootbus [dev] [boot_bus_width] [reset_boot_bus_width] [boot_mode]

设置总线位宽。

mmc partconf [dev ] [boot_ack ] [boot_partition ] [partition_access]

设置启动分区,dev 为mmc设备编号。boot_ack为是否应答。boot_partition用户选择发送到主机的引导数据。partition_access用户选择要访问的分区。

什么是netlink?

netlink提供的是内核态和用户态之间的通信机制,也可以用于用户态和用户态的两个进程之间通信。

netlink的优势

一般的用户态和内核空间通信方式有三种,ioctl,proc,netlink。而前两种都是单向的,而netlink可以实现双向通信。基于BSD socket和AF_NETLINK协议簇。使用32位的端口号寻址。每个netlink协议,通常与一个或者一组内核服务/组件相关联。NETLINK_ROUTE用于获取和设置路由与链路信息、NETLINK_KOBJECT_UEVENT用于内核向用户空间的udev进程发送通知等。

netlink的特点

  • 支持全双工,异步通信
  • 在内核空间使用专门的内核api接口
  • 支持多播,可以实现总线式订阅
  • 在内核端可以用于进程上下文和中断上下文
  • 用户空间使用标准BSD Socket接口

关键数据结构

image-20240805200041276

msghdr

我们知道socket消息的发送和接收函数一般有这几对:recv/send、readv/writev、recvfrom/sendto。当然还有recvmsg/sendmsg,前面三对函数各有各的特点功能,而recvmsg/sendmsg就是要囊括前面三对的所有功能,当然还有自己特殊的用途。msghdr的前两个成员就是为了满足recvfrom/sendto的功能,中间两个成员msg_iov和msg_iovlen则是为了满足readv/writev的功能,而最后的msg_flags则是为了满足recv/send中flag的功能,剩下的msg_control和msg_controllen则是满足recvmsg/sendmsg特有的功能。

sockaddr_nl

image-20240805200415939

1
2
3
4
5
6
7
struct sockaddr_nl
{
sa_family_t nl_family; /*该字段总是为AF_NETLINK */
unsigned short nl_pad; /* 目前未用到,填充为0*/
__u32 nl_pid; /* process pid */
__u32 nl_groups; /* multicast groups mask */为0代表不希望加入任何多播组
};
struct nlmsghdr

netlink报文消息由头和消息体构成。

1
2
3
4
5
6
7
8
struct nlmsghdr
{
__u32 nlmsg_len; /* Length of message including header */ 整个消息的长度,按字节计算。包括了Netlink消息头本身。
__u16 nlmsg_type; /* Message content */ 消息的类型,数据消息还是控制消息
__u16 nlmsg_flags; /* Additional flags */ 附加的额外信息
__u32 nlmsg_seq; /* Sequence number */
__u32 nlmsg_pid; /* Sending process PID */
};

用户空间使用netlink

1.创建socket
1
2
3
4
int socket(int domain, int type, int protocol)
domain指代地址族,即AF_NETLINK;
套接字类型为SOCK_RAW或SOCK_DGRAM,因为netlink是一个面向数据报的服务;
protocol选择该套接字使用哪种netlink特征。
1
bind(fd, (struct sockaddr*)&, nladdr, sizeof(nladdr));
3.发送netlink消息

为了发送一条netlink消息到内核或者其他的用户空间进程,另外一个struct sockaddr_nl nladdr需要作为目的地址,这和使用sendmsg()发送一个UDP包是一样的。

  • 如果该消息是发送至内核的,那么nl_pid和nl_groups都置为0.
  • 如果消息是发送给另一个进程的单播消息,nl_pid是另外一个进程的pid值而nl_groups为零。
  • 如果消息是发送给一个或多个多播组的多播消息,所有的目的多播组必须bitmask必须or起来从而形成nl_groups域。sendmsg(fd, &, msg, 0);
4.接收netlink消息

一个接收程序必须分配一个足够大的内存用于保存netlink消息头和消息负载。然后其填充struct msghdr msg,再使用标准的recvmsg()函数来接收netlink消息。

当消息被正确的接收之后,nlh应该指向刚刚接收到的netlink消息的头。nladdr应该包含接收消息的目的地址,其中包括了消息发送者的pid和多播组。同时,宏NLMSG_DATA(nlh),定义在netlink.h中,返回一个指向netlink消息负载的指针。调用close(fd)关闭fd描述符所标识的socket;recvmsg(fd, &, msg, 0);

内核空间使用netlink

1
2
3
4
struct sock *netlink_kernel_create(struct net *net,
int unit,unsigned int groups,
void (*input)(struct sk_buff *skb),
struct mutex *cb_mutex,struct module *module);
发送单播信息
1
2
int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock)
ssk为kernel create返回的socket,skb存放消息,data段指向netlink消息结构,skb控制块保存了消息的地址信息。pid为接收消息的进程信息。nonblock表示是否阻塞。
发送广播信息
1
int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, u32 group, gfp_t allocation)
1
int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, u32 group, gfp_t allocation)

设备树

argparse介绍

argparse 模块是 Python 内置的一个用于==命令项选项与参数解析==的模块,argparse 模块可以让人轻松编写用户友好的命令行接口。通过在程序中定义好我们需要的参数,然后 argparse 将会从 sys.argv 解析出这些参数。argparse 模块还会自动生成帮助和使用手册,并在用户给程序传入无效参数时报出错误信息。

官方地址:https://docs.python.org/zh-cn/3/library/argparse.html#argumentparser-objects

使用介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import argparse

# 创建一个解析器。创建argumentparser对象
#大多数对argumentparser构造方法的调用都会使用description=关键词参数。这个参数简要描述
parser = argparse.ArgumentParser(description='test')

# 调用add_argument方法添加参数信息是通过调用add_argument方法完成的。
parser.add_argument('--sparse', action='store_true', default=False, help='GAT with sparse version or not.')
parser.add_argument('--seed', type=int, default=72, help='Random seed.')
parser.add_argument('--epochs', type=int, default=10000, help='Number of epochs to train.')

# 使用parse_args解析添加的参数
args = parser.parse_args()
print(args.sparse)
print(args.seed)
print(args.epochs)

add_argument()

其中,这个方法定义了如何解析命令行参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ArgumentParser.add_argument(name or flags...[, action][, nargs][, const][, default][, type][, choices][, required][, help][, metavar][, dest])

name or flags:选项字符串的名字或者列表,例如foo或者-f,--foo
avtion:命令行遇到参数时的动作。默认值是store
(action=storce_true命令行遇到参数时的动作,默认是store,只要运行该变量有传参就将该变量设置为true)
store_const:表示赋值为const
append:将遇到的值存储成列表,如果参数重复会保存多个值。
append_const,将参数规范中定义的一个值保存到一个列表;
count,存储遇到的次数;此外,也可以继承 argparse.Action 自定义参数解析;
nargs - 应该读取的命令行参数个数,可以是具体的数字,或者是?号,当不指定值时对于 Positional argument 使用 default,对于 Optional argument 使用 const;或者是 * 号,表示 0 或多个参数;或者是 + 号表示 1 或多个参数。
const - action 和 nargs 所需要的常量值。
default - 不指定参数时的默认值。
type - 命令行参数应该被转换成的类型。
choices - 参数可允许的值的一个容器。
required - 可选参数是否可以省略 (仅针对可选参数)。
help - 参数的帮助信息,当指定为 argparse.SUPPRESS 时表示不显示该参数的帮助信息.
metavar - 在 usage 说明中的参数名称,对于必选参数默认就是参数名称,对于可选参数默认是全大写的参数名称.
dest - 解析后的参数名称,默认情况下,对于可选参数选取最长的名称,中划线转换为下划线.

命令行下单点调试的方式,python -m pdb xxx.py

补充串口库

pyserical库可以非常方便和串口的通讯

官方文档

https://pyserial.readthedocs.io/en/latest/pyserial.html

1
2
3
4
5
6
import serial.tools.list_ports

# 列出当前连接的串口设备
ports_list = list(serial.tools.list_ports.comports())
for comport in ports_list:
print(comport[0], comport[1])

打开串口,参数说明

1
__init__(port=None, baudrate=9600, bytesize=EIGHTBITS, parity=PARITY_NONE, stopbits=STOPBITS_ONE, timeout=None, xonxoff=False, rtscts=False, write_timeout=None, dsrdtr=False, inter_byte_timeout=None, exclusive=None)

bytesize : 数据位,可取值five six seven eight等等

parity : 校验位,可取值none,even,odd,mask,spcae等等。

stop:停止位,one,two,five等等

timeout:超时时间,读超时时间,可取值为 None, 0 或者其他具体数值(支持小数)。当设置为 None 时,表示阻塞式读取,一直读到期望的所有数据才返回;当设置为 0 时,表示非阻塞式读取,无论读取到多少数据都立即返回;当设置为其他数值时,表示设置具体的超时时间(以秒为单位),如果在该时间内没有读取到所有数据,则直接返回

xonxoff:软件流控。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#举例 
import serial.tools.list_ports
s = serial.Serial('COM75', 115200, timeout=0.5)
print(s.isOpen()) # True

#发送数据 发送数据使用write方法,发送的数据只能是byte类型,因此需要对发送的字符串进行编码操作
cmd = 'ifconfig\r\n' # 命令带换行符
length = s.write(cmd.encode('utf-8'))
# 发送字符串
str = "serial"
ser.write(str.encode())
# 发送 bytes
data = [0x55,0xAA,0x5A]
ser.write(data)
# 发送数字
num = 100
ser.write(num.to_bytes(1,"little")) # 长度1,小端模式

#读取数据 可以使用read readall readlines...
#read默认读取一个字节,可以通过传入参数指定每次读取的字节数,返回值bytes类型
#readall读取串口接收的全部数据,返回bytes类型
#readlines读取多行数据,返回list类型,列表元素类型为bytes类型
print(s.read(1024))
s.read()[0] --》 读取一个字节
print(s.readlines())
print(s.readall())

#关闭串口 直接调用close方法即可
s.close()

#其他方法
in_waiting():返回接收缓存中的字节数
flush():等待所有数据写出
flushinput():丢弃接收缓存中的所有数据
flushOutput():终止当前写操作,并丢弃发送缓存中的数据。

备份区域以及RTC介绍

摄影参数介绍

  • 白平衡:通过调整色温尽量保持白色为原本的白色,即平衡白色的颜色。(本质是通过调整色温来调整蓝色/红色的互补色 )(90%的场景可以使用自动白平衡)

    • 白色优先/氛围优先
    • 环境中光源很多的时候,自动白平衡可能效果不好,手动不知道设置什么的时候,设置一下白卡校准。延时拍摄需要手动设置,不然会收到忽然出现物体的影响。RAW格式后期可以无损更改白平衡
  • 色温:颜色的温度,色温越高 颜色越偏蓝,色温约低,颜色越偏红。

  • 色相:后期修改偏色,颜色发绿等等。

  • 对焦:主要依靠镜头来完成。镜头外圈单位为m,内圈单位为inch,AF自动对焦,MF手动对焦 (当环境较暗,色彩很多的时候,自动对焦可能会不准。镜头有最小对焦距离,不得小于此,否则会无法对焦。)

  • AF-S:单次对焦,移动相机对焦距离也不会改变。

  • AF-A:自动检测物体是否移动。

  • AF-C:连续对焦模式。(80%)

  • DMF:自动对焦后,可手动精细对焦调节

  • 广域对焦:屏幕范围内任何都可以对焦

  • 点对焦SML,小中大。自由选择对焦点。

  • 扩展点:点无法对焦的时候在附近找扩展点进行对焦

  • 跟踪对焦:选择对焦区域。对焦点会一直跟着指定物体。

  • AF过渡速度:从一个对焦点移动到另一个对焦点的速度

  • AF转移灵敏度:如果焦点前有物体掠过的时候,是否会快速对焦到物体身上。

  • 测光模式

    • 全局测光:分割画面,单独测光,提高焦点附近权重,计算均值。(90%)
    • 中心测光:对画面中央物体进行测光,比如拍人的时候。
    • 点测光;顾名思义。
  • 曝光补偿:白+黑-,拍摄人物可以适当增加一点曝光补偿。因为人体反射率25%左右。相机自动曝光会拉低曝光值,导致人物偏暗。打开直方图也可以。

  • 光圈:F值。数字越大,光圈越小。

    • 光圈越大,进光亮越多。
    • 光圈越大,虚化越明显,景深越浅。拍摄人物的时候放大光圈,拍摄风景的时候缩小光圈。
  • 快门:单位:s 1/100秒。会计算0.01s的进光量到传感器。

    • 快门速度越慢,进光量越多。
    • 快门速度还会影响拖影。 运动速度较快的设备使用较快的快门速度。轨迹则用慢速快门。
    • 一般可以设置快门速度值比焦段数值更高。
    • 果冻效应:物体运动过快导致每一行图像数据有时间差。导致图片会倾斜。用全域快门来解决。因为全域快门一次读取的是所有的数据。
    • 电子快门,不用机械快门。但是画质会减少,因为cpu还要处理电子快门逻辑。
    • 电子前lian快门。
    • 拍摄视频的时候的快门。和帧数相关。快门速度越快,每一帧记录物体移动时间越少。动态模糊越少。
    • 设置相机的快门速度一般为帧数的2倍数。
  • ISO:ISO越高,画面越亮,噪点越多。增加增益,通电量。一般情况通过光圈和快门来控制曝光,实在没办法了,才会通过ISO提高。增加ISO的时候信噪比会提高。会放大本底噪声。主要是由于进光量不足,被迫只能放大信号,导致噪点被放大变得可见了。

挡位介绍

  • auto:全自动
  • P:程序自动曝光+手动曝光补偿
  • A:光圈优先,相机自动调整快门和ISO。 拍摄人像的时候,大光圈优先
  • S:快门优先挡位,相机自动调整光圈ISO。拍摄运动物体的时候。
  • C1:C2 C3,自定义挡位。

布隆过滤器介绍

基本概念:它实质上是一个很长的二进制向量和一系列随机映射函数 (Hash函数)。

作用:它是一个空间效率高的概率型数据结构,用来告诉你:一个元素一定不存在或者可能存在

优点:

  • 在存储空间和时间都是常数,即hash函数的个数
    
  • Hash 函数相互之间没有关系,方便由硬件并行实现。
    
  • 布隆过滤器不需要存储元素本身,在某些对保密要求非常严格的场合有优势。
    
  • 布隆过滤器可以表示全集,其它任何数据结构都不能。
    

缺点:

  • 有误判率存在
  • 不支持删除

适用场景:

  • 预防缓存穿透:布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在。
  • 网络爬虫:布隆过滤器可以用来去重已经爬取过的URL。
  • 邮箱的垃圾邮件过滤。
  • 黑白名单。

原理

结构

布隆过滤器实现原理就是一个超大位数的数组(BitMap)和多个不同Hash算法函数。与寻常数组不同的是,BitMap一个数组元素占一个bit,这一特性决定了BitMap能够极大地节省空间

image-20240509090000811

添加元素

将要添加的元素分别通过k个哈希函数计算得到k个哈希值,这k个hash值对应位数组上的k个位置,然后将这k个位置设置为1。

image-20240509090026138

当不同元素在计算到相同的值后,依旧保持这一位为1即可。

image-20240509084931019

查询元素

将要查询的元素分别通过k个哈希函数计算得到k个哈希值,这k个hash值对应位数组上的k个位置。如果这k个位置中有一个位置为0,则此元素一定不存在集合中。如果这k个位置全部为1,则这个元素可能存在。

误判

需要注意的是,布隆过滤器无法确定元素存在,只能确定元素不存在。出现的原因是多个输入经过哈希之后在相同的bit位置1了,这样就无法判断究竟是哪个输入产生的,因此误判的根源在于相同的 bit 位被多次映射且置 1。

这种情况也造成了布隆过滤器的删除问题,即布隆过滤器不存在删除操作。因为布隆过滤器的每一个 bit 并不是独占的,很有可能多个元素共享了某一位。如果我们直接删除这一位的话,会影响其他的元素。

应用场景

防止缓存穿透。缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。使用布隆过滤器能够避免频繁查询不存在的数据,减轻数据库的压力。

业务场景中判断用户是否阅读过某视频或文章,比如抖音或头条,当然会导致一定的误判,但不会让用户看到重复的内容。

gun hash表, 主要是利用 Bloom Filter, 在常量时间内判断, 字符是否存在, 以及对应 .dynsym 的位置. 使用 gcc -g -o hello -Wl,--hash-style=sysv(gnu) hello.c 可以产生旧版本的 hash 表.

0%