【Redis篇】Redis 数据类型入门:全局命令、单线程原理与 String 字符串
文章目录
Redis 数据类型入门:全局命令、单线程原理与 String 字符串
一、前言
💬 这一篇讲什么:在正式学习五种数据类型之前,先打好基础;然后深入讲解最核心的数据类型 —— String
🚀 核心内容:
- Redis 的全局命令有哪些?如何对任意 key 进行通用操作?
- Redis 每种数据类型的底层内部编码是什么?为什么要有多种编码?
- Redis 单线程模型是怎么运转的?为什么单线程还能这么快?
- String 类型的所有命令和典型使用场景
上一篇把 Redis 环境搭起来了。从这一篇开始,正式进入 Redis 最核心的内容:数据类型。在开始之前,有一些基础知识必须先铺垫清楚,否则后面很多命令的行为会让人摸不着头脑。
二、全局命令
Redis 有五种数据类型,但不管 value 是哪种类型,key 本身永远是字符串,而且有一批命令是对所有类型的 key 都通用的,这些命令叫做全局命令。先把这些通用命令搞清楚,后面学每种数据类型时会少很多困惑。
2.1 KEYS —— 查找匹配的 key
返回所有满足匹配模式(pattern)的 key。
语法:
KEYS pattern
时间复杂度:O(N),N 是数据库中 key 的总数。
支持的通配符:
| 模式 | 含义 | 示例 |
|---|---|---|
? |
匹配任意单个字符 | h?llo 匹配 hello、hallo、hxllo |
* |
匹配任意数量字符(包括零个) | h*llo 匹配 hllo、heeeello |
[ae] |
匹配括号内的任意一个字符 | h[ae]llo 匹配 hello、hallo,不匹配 hillo |
[^e] |
匹配不在括号内的字符 | h[^e]llo 匹配 hallo、hbllo,不匹配 hello |
[a-b] |
匹配字符范围 | h[a-b]llo 匹配 hallo、hbllo |
示例:
redis> MSET firstname Jack lastname Stuntman age 35
"OK"
redis> KEYS *name*
1) "firstname"
2) "lastname"
redis> KEYS a??
1) "age"
redis> KEYS *
1) "age"
2) "firstname"
3) "lastname"
❗ 重要警告:
KEYS *会遍历整个数据库中所有的 key,时间复杂度是 O(N)。在生产环境中,如果 Redis 存储了大量数据,执行KEYS *会造成 Redis 阻塞,期间所有其他客户端的请求都会被卡住。生产环境中禁止使用 KEYS 命令,需要遍历 key 时应使用后面章节会讲到的SCAN命令。
2.2 EXISTS —— 判断 key 是否存在
判断指定的一个或多个 key 是否存在。
语法:
EXISTS key [key ...]
时间复杂度:O(1)
返回值:存在的 key 的个数(注意:传入多个相同的 key,每个都会被单独计数)。
示例:
redis> SET key1 "Hello"
"OK"
redis> EXISTS key1
(integer) 1
redis> EXISTS nosuchkey
(integer) 0
redis> SET key2 "World"
"OK"
redis> EXISTS key1 key2 nosuchkey
(integer) 2
2.3 DEL —— 删除 key
删除指定的一个或多个 key,不存在的 key 会被忽略。
语法:
DEL key [key ...]
时间复杂度:O(1)
返回值:实际删除掉的 key 的个数。
示例:
redis> SET key1 "Hello"
"OK"
redis> SET key2 "World"
"OK"
redis> DEL key1 key2 key3
(integer) 2
key3 不存在,所以只删掉了 2 个。
2.4 EXPIRE 和 TTL —— 过期时间管理
EXPIRE:设置过期时间
为指定的 key 设置秒级的过期时间(TTL,Time To Live)。
语法:
EXPIRE key seconds
时间复杂度:O(1)
返回值:1 表示设置成功,0 表示设置失败(key 不存在)。
示例:
redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 10
(integer) 1
redis> TTL mykey
(integer) 10
TTL:查询剩余过期时间
获取指定 key 的剩余过期时间,秒级。
语法:
TTL key
时间复杂度:O(1)
返回值:
- 正整数:剩余的秒数
-1:key 存在但没有设置过期时间-2:key 不存在
示例:
redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 10
(integer) 1
redis> TTL mykey
(integer) 10
# 等待 10 秒后
redis> TTL mykey
(integer) -2
redis> EXISTS mykey
(integer) 0
键的过期机制如下:设置 key 并执行 EXPIRE 之后,Redis 会在指定秒数后自动淘汰这个 key,之后无论是 GET 还是 EXISTS,都会返回 key 不存在的结果。
💡
EXPIRE和TTL都有对应的毫秒版本:PEXPIRE和PTTL,用法完全一致,只是时间单位换成了毫秒,适合需要高精度过期控制的场景。
2.5 TYPE —— 查询 key 的数据类型
返回 key 对应的 value 的数据类型。
语法:
TYPE key
时间复杂度:O(1)
返回值:none(key不存在)、string、list、set、zset、hash、stream。
示例:
redis> SET key1 "value"
"OK"
redis> LPUSH key2 "value"
(integer) 1
redis> SADD key3 "value"
(integer) 1
redis> TYPE key1
"string"
redis> TYPE key2
"list"
redis> TYPE key3
"set"
三、数据结构与内部编码
3.1 两个层次
TYPE 命令返回的是 Redis 对外暴露的数据结构类型,也就是我们使用时感知到的那一层:string、list、hash、set、zset。
但实际上,Redis 在底层对每种数据结构都有多种内部编码实现,Redis 会根据当前数据的规模和特征,自动选择最合适的那一种:
| 数据结构 | 内部编码 |
|---|---|
| string | raw、int、embstr |
| hash | hashtable、ziplist |
| list | linkedlist、ziplist(3.2之后合并为 quicklist) |
| set | hashtable、intset |
| zset | skiplist、ziplist |
可以通过 OBJECT ENCODING 命令查询某个 key 当前使用的内部编码:
127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> object encoding hello
"embstr"
127.0.0.1:6379> lpush mylist a b c
(integer) 3
127.0.0.1:6379> object encoding mylist
"quicklist"
3.2 为什么要这样设计
这个设计有两个核心好处:
好处一:可以升级内部编码而不影响使用者。 用户使用的命令和数据结构完全不变,Redis 内部可以悄悄换掉底层实现。比如 Redis 3.2 引入了 quicklist(结合了 ziplist 和 linkedlist 两者的优势),用户完全无感知,代码一行不用改,性能却提升了。
好处二:不同场景下选用最优实现,兼顾性能和内存。 以 list 为例:元素少时用 ziplist(压缩列表,内存紧凑),元素多时用 linkedlist(链表,读写更快)。Redis 会根据配置的阈值自动切换,用户不需要关心。
四、单线程架构
4.1 单线程模型是什么意思
很多人误解"Redis 是单线程的"这句话。准确的说法是:Redis 处理命令的核心逻辑是单线程的(6.0 之后网络 IO 引入了多线程,但命令执行仍然是单线程)。
来看一个具体的例子。假设有三个客户端同时向 Redis 发命令:
# 客户端 1
SET hello world
# 客户端 2
INCR counter
# 客户端 3
INCR counter
从宏观上看,三个客户端似乎同时在发请求。但在微观上,这些命令到达 Redis 服务端的时间有先后(哪怕只差几微秒),Redis 内部只有一个命令处理队列,所有命令被串行地依次执行,就像银行只有一个服务窗口,所有人排队等候一样。
正因为是串行的,两条 INCR counter 命令无论顺序如何,最终结果一定是 2,不会出现并发竞争导致结果错误的情况。这是单线程模型最大的好处之一。
4.2 单线程为什么还这么快
直觉上,单线程处理能力应该比多线程弱。但 Redis 单线程能达到每秒数万乃至十万次的处理能力,原因有三:
原因一:纯内存操作。 Redis 把所有数据存在内存中,内存访问耗时约 100 纳秒,而磁盘寻道需要 10 毫秒以上,差了 10 万倍。内存操作之快,让单线程的"串行瓶颈"根本不是问题。
原因二:非阻塞 IO(IO 多路复用)。 Redis 使用 epoll 实现 IO 多路复用。简单来说,epoll 允许一个线程同时监听大量网络连接,哪个连接有数据来了就去处理哪个,不会因为等待某个客户端而阻塞其他客户端。Redis 把连接的建立、数据读写、连接关闭全部注册为事件,由事件循环(Event Loop)驱动,在网络 IO 上几乎不浪费时间。
[客户端 1]
[客户端 2] ──→ epoll 事件监听 ──→ Redis Event Loop(单线程)
[客户端 N] ↑
有数据就触发
原因三:避免了多线程的额外开销。 多线程并不是免费的——线程切换有开销,多个线程竞争共享数据需要加锁(锁的开销有时候非常大),还容易出现死锁等复杂问题。单线程模型彻底规避了这些问题,代码也更简洁。
4.3 单线程的致命弱点
单线程带来了简洁和高效,但也有一个不可忽视的问题:如果某条命令执行时间过长,会阻塞所有其他客户端的请求。
因为只有一个处理窗口,如果某个命令执行了几秒钟,期间所有排队的其他命令都在等待,客户端会超时,用户会感受到明显的卡顿。
这就是为什么 Redis 的命令设计原则是"快":所有命令的时间复杂度都尽量控制在 O(1) 或 O(log N),对于 O(N) 的命令(比如 KEYS *、HGETALL 大哈希)需要格外谨慎,在生产环境中要评估数据规模再使用。
结论:Redis 是面向快速执行场景的数据库,命令越快越好,耗时命令要慎用。
五、String 字符串
String 是 Redis 中最基础的数据类型,也是使用最广泛的类型。有几点需要先说清楚:
第一,Redis 所有 key 都是字符串类型。 其他四种数据类型是 value 的类型,key 永远是字符串。
第二,String 类型的 value 可以是以下任意一种:
- 普通字符串:
"hello world" - JSON / XML 等格式字符串:
'{"id":1,"name":"James"}' - 数字(整型或浮点型):
42、3.14 - 二进制数据(图片、音频等的字节流)
唯一的限制是:单个 String 的值最大不能超过 512 MB。
第三,Redis 是按照二进制流存储字符串的,不处理字符集编码问题。 客户端传入什么编码,Redis 原样存储,读出来什么编码是客户端的事。
5.1 基本命令
SET —— 设置值
将 string 类型的 value 设置到 key 中。如果 key 已存在,无论原来是什么类型,都会被覆盖,原有的 TTL 也会清除。
语法:
SET key value [EX seconds] [PX milliseconds] [NX|XX]
选项说明:
| 选项 | 含义 |
|---|---|
EX seconds |
设置秒级过期时间 |
PX milliseconds |
设置毫秒级过期时间 |
NX |
只在 key 不存在时才设置(Not eXists) |
XX |
只在 key 存在时才设置(eXists) |
返回值:设置成功返回 OK;因 NX/XX 条件不满足而未执行则返回 (nil)。
示例:
# 基本设置
redis> SET mykey "Hello"
OK
redis> GET mykey
"Hello"
# NX:key 不存在才设置
redis> SET mykey "World" NX
(nil) # mykey 已存在,设置失败
# 先删除
redis> DEL mykey
(integer) 1
# XX:key 存在才设置
redis> SET mykey "World" XX
(nil) # mykey 不存在,设置失败
# NX 在 key 不存在时成功
redis> SET mykey "World" NX
OK
# 设置带过期时间
redis> SET mykey "Will expire in 10s" EX 10
OK
redis> GET mykey
"Will expire in 10s"
# 10 秒后
redis> GET mykey
(nil)
三种设置模式的执行逻辑:
SET key value:无论 key 是否存在,直接覆盖写入。SET key value NX(等价于SETNX key value):只有 key 不存在时才写入,已存在则不操作。SET key value XX:只有 key 已存在时才覆盖,不存在则不操作。
GET —— 获取值
获取 key 对应的 value。key 不存在返回 nil;如果 value 不是 string 类型会报错。
语法:
GET key
时间复杂度:O(1)
示例:
redis> GET nonexisting
(nil)
redis> SET mykey "Hello"
"OK"
redis> GET mykey
"Hello"
# 对非 string 类型执行 GET 会报错
redis> HSET mykey name Bob
(integer) 1
redis> GET mykey
(error) WRONGTYPE Operation against a key holding the wrong kind of value
MSET 和 MGET —— 批量操作
MSET 一次性设置多个 key 的值;MGET 一次性获取多个 key 的值。
语法:
MSET key value [key value ...]
MGET key [key ...]
时间复杂度:O(N),N 是 key 的数量。
示例:
redis> MSET key1 "Hello" key2 "World"
"OK"
redis> MGET key1 key2 nonexisting
1) "Hello"
2) "World"
3) (nil)
为什么批量命令性能更高?
假设网络往返耗时 1ms,每条命令执行耗时 0.1ms:
| 操作方式 | 总耗时 |
|---|---|
| 执行 1000 次 GET | 1000 × 1ms + 1000 × 0.1ms = 1100ms |
| 执行 1 次 MGET(1000 个 key) | 1 × 1ms + 1000 × 0.1ms = 101ms |
批量操作把 1000 次网络往返压缩成了 1 次,性能提升接近 10 倍。
不过要注意:批量操作一次携带的 key 数量也不能无限多,否则单条命令执行时间过长,会阻塞 Redis 服务端。实践中通常建议单次批量不超过几百到几千个 key,具体根据数据大小评估。
SETNX —— 不存在时才设置
只在 key 不存在的情况下才设置值。等价于 SET key value NX。
语法:
SETNX key value
返回值:1 表示设置成功,0 表示 key 已存在未设置。
示例:
redis> SETNX mykey "Hello"
(integer) 1
redis> SETNX mykey "World"
(integer) 0
redis> GET mykey
"Hello"
SETNX 在分布式锁的实现中有重要作用,后续专门讲分布式锁时会详细展开。
5.2 计数命令
Redis 对 String 类型提供了一批专门针对数字值的原子性自增自减命令,这是 Redis 在计数场景下的核心能力。
INCR —— 自增 1
将 key 对应的数字值加 1。如果 key 不存在,视为原值为 0,执行后结果为 1。如果 value 不是整数,或超过 64 位有符号整型范围,则报错。
语法:
INCR key
时间复杂度:O(1)
示例:
redis> EXISTS mykey
(integer) 0
redis> INCR mykey
(integer) 1 # key 不存在,从 0 开始加 1
redis> SET mykey "10"
"OK"
redis> INCR mykey
(integer) 11
# 非整数会报错
redis> SET mykey "not a number"
"OK"
redis> INCR mykey
(error) value is not an integer or out of range
INCRBY —— 自增指定步长
将 key 对应的数字值加上指定的整数值。
语法:
INCRBY key increment
示例:
redis> SET mykey "10"
"OK"
redis> INCRBY mykey 3
(integer) 13
redis> INCRBY mykey -5
(integer) 8
DECR 和 DECRBY —— 自减
DECR 将值减 1;DECRBY 将值减去指定的整数。逻辑和 INCR/INCRBY 完全对称。
redis> SET mykey "10"
"OK"
redis> DECR mykey
(integer) 9
redis> DECRBY mykey 3
(integer) 6
INCRBYFLOAT —— 浮点数自增
将 key 对应的值加上指定的浮点数。支持负数(相当于减法)。支持科学计数法。
语法:
INCRBYFLOAT key increment
示例:
redis> SET mykey 10.50
"OK"
redis> INCRBYFLOAT mykey 0.1
"10.6"
redis> INCRBYFLOAT mykey -5
"5.6"
redis> SET mykey 5.0e3
"OK"
redis> INCRBYFLOAT mykey 2.0e2
"5200"
💡 在很多编程语言里,实现计数器需要用 CAS(Compare And Swap)机制来保证并发安全,这会有一定的 CPU 开销。但在 Redis 里完全不需要这些,因为命令是单线程串行执行的,两条
INCR命令不可能同时执行,结果天然正确,没有竞态条件。
5.3 字符串操作命令
APPEND —— 追加内容
在 key 对应的 string 末尾追加内容。如果 key 不存在,效果等同于 SET。
语法:
APPEND key value
返回值:追加后 string 的总长度。
示例:
redis> EXISTS mykey
(integer) 0
redis> APPEND mykey "Hello"
(integer) 5
redis> APPEND mykey " World"
(integer) 11
redis> GET mykey
"Hello World"
STRLEN —— 获取字符串长度
获取 key 对应 string 的字节长度(注意是字节数,不是字符数,中文字符在 UTF-8 下占 3 字节)。key 不存在返回 0。
语法:
STRLEN key
时间复杂度:O(1)
示例:
redis> SET mykey "Hello world"
"OK"
redis> STRLEN mykey
(integer) 11
redis> STRLEN nonexisting
(integer) 0
GETRANGE —— 获取子串
返回 string 的子串,由起始下标 start 和结束下标 end 决定,左闭右闭。支持负数索引:-1 代表最后一个字符,-2 代表倒数第二个,以此类推。下标越界会自动调整。
语法:
GETRANGE key start end
时间复杂度:O(N),N 为子串长度,通常视为 O(1)。
示例:
redis> SET mykey "This is a string"
"OK"
redis> GETRANGE mykey 0 3
"This"
redis> GETRANGE mykey -3 -1
"ing"
redis> GETRANGE mykey 0 -1
"This is a string" # 等同于获取整个字符串
redis> GETRANGE mykey 10 100
"string" # 超出范围自动截断
SETRANGE —— 覆盖子串
从指定的偏移位置开始,用新的 value 覆盖原有字符串的对应部分。
语法:
SETRANGE key offset value
返回值:修改后 string 的总长度。
示例:
redis> SET key1 "Hello World"
"OK"
redis> SETRANGE key1 6 "Redis"
(integer) 11
redis> GET key1
"Hello Redis"
5.4 命令速查表
| 命令 | 执行效果 | 时间复杂度 |
|---|---|---|
SET key value |
设置 key 的值 | O(1) |
GET key |
获取 key 的值 | O(1) |
MSET key value [...] |
批量设置多个 key | O(k),k 为键个数 |
MGET key [...] |
批量获取多个 key | O(k),k 为键个数 |
SETNX key value |
key 不存在时才设置 | O(1) |
INCR key |
值 +1 | O(1) |
DECR key |
值 -1 | O(1) |
INCRBY key n |
值 +n | O(1) |
DECRBY key n |
值 -n | O(1) |
INCRBYFLOAT key n |
浮点数值 +n | O(1) |
APPEND key value |
追加内容 | O(1) |
STRLEN key |
获取字符串长度 | O(1) |
GETRANGE key start end |
获取子串 | O(n),通常 O(1) |
SETRANGE key offset value |
覆盖子串 | O(n),通常 O(1) |
5.5 内部编码
String 类型在底层有三种内部编码实现,Redis 会根据 value 的内容自动选择:
| 内部编码 | 使用条件 | 说明 |
|---|---|---|
int |
value 是 64 位有符号整数 | 直接用整型存储,最节省内存 |
embstr |
value 是长度 ≤ 39 字节的字符串 | 紧凑存储,只分配一次内存 |
raw |
value 是长度 > 39 字节的字符串 | 常规字符串存储 |
# int 编码
127.0.0.1:6379> set key 6379
OK
127.0.0.1:6379> object encoding key
"int"
# embstr 编码(≤39 字节的短字符串)
127.0.0.1:6379> set key "hello"
OK
127.0.0.1:6379> object encoding key
"embstr"
# raw 编码(>39 字节的长字符串)
127.0.0.1:6379> set key "one string greater than 39 bytes ........"
OK
127.0.0.1:6379> object encoding key
"raw"
六、String 的典型使用场景
6.1 缓存(Cache)
这是 Redis String 最核心的使用场景。把数据库里的热数据序列化后存入 Redis,后续请求优先从 Redis 读取,命中则直接返回,未命中再查数据库并回填缓存。
典型架构如下:
用户请求
↓
先查 Redis 缓存(key = "user:info:{uid}")
├── 命中(hit)→ 直接返回数据
└── 未命中(miss)→ 查 MySQL → 结果写入 Redis(带过期时间)→ 返回数据
伪代码示意:
def get_user_info(uid):
key = "user:info:" + str(uid)
# 先查缓存
value = redis.get(key)
if value is not None:
return json.loads(value) # 缓存命中,直接返回
# 缓存未命中,查数据库
user_info = mysql.query("SELECT * FROM user_info WHERE uid = %s", uid)
if user_info is None:
return None # 用户不存在
# 写入缓存,设置 1 小时过期(防止数据腐烂)
redis.set(key, json.dumps(user_info), ex=3600)
return user_info
设置过期时间(EX 3600)很重要:即使数据库里的数据发生了变化,缓存最多也只会"过时"一小时,之后自动失效,下次请求会重新从数据库读取最新数据。
💡 键名设计建议:Redis 没有表和字段的概念,建议使用
业务名:对象名:唯一标识:属性的格式命名键,比如user:info:1001、video:playcount:5253。这样既能防止不同业务的键名冲突,也便于维护。键名过长会影响 Redis 性能,必要时可以使用团队内认可的缩写。
6.2 计数器(Counter)
利用 INCR 系列命令实现原子性计数,天然线程安全,性能极高。
以视频播放量为例:
def increment_play_count(video_id):
key = "video:playcount:" + str(video_id)
count = redis.incr(key) # 原子性 +1,返回最新计数
return count
每次用户播放视频,调用一次 INCR,Redis 自动完成加 1 操作。可以异步地将 Redis 中的计数定期同步回 MySQL,避免高频写库。
6.3 共享 Session
分布式 Web 服务通常有多台应用服务器,负载均衡会把用户请求打到不同的机器上。如果 Session 存在每台机器本地,用户可能每次请求都被分到不同的机器,导致需要反复登录。
解决方案是把 Session 集中存储在 Redis 中:
用户
↓
[负载均衡器]
├── [应用服务器 1] ──→ [Redis:Session 集中存储]
├── [应用服务器 2] ──→
└── [应用服务器 n] ──→
无论用户被分到哪台服务器,都从 Redis 里读写 Session,数据始终一致,也不会丢失登录状态。
6.4 手机验证码
验证码场景有两个核心需求:验证码有效期(比如 5 分钟失效)和发送频率限制(比如同一手机号 1 分钟内最多发 5 次)。两个需求都可以用 Redis String 的过期时间和 INCR 优雅地实现。
核心逻辑:
def send_verification_code(phone_number):
# 频率限制 key,1 分钟内有效
limit_key = "sms:limit:" + phone_number
# NX 保证第一次设置时才初始化,EX 60 设置 1 分钟过期
r = redis.set(limit_key, 1, ex=60, nx=True)
if r is None:
# key 已存在,说明这一分钟内已经发过了
count = redis.incr(limit_key)
if count > 5:
return None # 超出频率限制,拒绝发送
# 生成随机 6 位验证码
code = generate_random_code()
# 存入 Redis,5 分钟有效
code_key = "sms:code:" + phone_number
redis.set(code_key, code, ex=300)
# 通过短信接口发送
send_sms(phone_number, code)
return code
def verify_code(phone_number, input_code):
code_key = "sms:code:" + phone_number
stored_code = redis.get(code_key)
if stored_code is None:
return False # 验证码已过期或不存在
return stored_code == input_code
整个流程用到了 SET NX EX(原子性设置 + 过期时间)和 INCR(原子性计数),不需要任何锁操作,逻辑清晰,并发安全。
七、总结
现在你已经掌握了:
✅ 全局命令:KEYS(生产环境禁用)、EXISTS、DEL、EXPIRE、TTL、TYPE
✅ 内部编码机制:对外数据结构与内部编码的两层设计,以及这样设计的好处
✅ 单线程架构:命令串行执行、IO 多路复用(epoll)、纯内存操作 —— 三者共同造就了 Redis 的高性能
✅ 单线程弱点:慢命令会阻塞所有客户端,生产环境要谨慎
✅ String 全部命令:SET/GET/MSET/MGET/SETNX、INCR/DECR 系列、APPEND/STRLEN/GETRANGE/SETRANGE
✅ String 内部编码:int(整数)、embstr(≤39字节)、raw(>39字节)
✅ String 典型场景:缓存、计数器、共享Session、手机验证码
7.1 重点注意事项
| 注意事项 | 说明 |
|---|---|
KEYS * 禁止在生产环境使用 |
时间复杂度 O(N),会阻塞 Redis |
| 批量命令注意 key 数量 | 单次批量过多同样会导致阻塞 |
| 计数命令只对整数有效 | 浮点数要用 INCRBYFLOAT |
| SET 会清除原有 TTL | 覆盖写时需注意过期时间是否需要重新设置 |
| 键名设计要规范 | 使用 业务:对象:id 格式,避免冲突 |
下一篇预告:Redis Hash 哈希类型 —— 全部命令详解、内部编码机制、与字符串存储方式的对比,以及在用户信息存储等场景中的实战应用。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)