当前位置: 首页 > news >正文

【redis】Redis数据类型(三)List类型

目录

  • List类型介绍
    • 特点
  • List数据结构
    • 附:3.2以前的版本(介绍一下压缩列表和双向链表)
      • 压缩列表ZipList
      • 双向链表LinkedList
  • 常用命令
      • lpush
        • 示例
      • lpushx
        • 示例
      • rpush
        • 示例
      • rpushx
        • 示例
      • LPOP
        • 示例
      • RPOP
        • 示例
      • BLPOP
        • 非阻塞行为
        • 阻塞行为
        • 相同的 key 被多个客户端同时阻塞
        • 在 MULTI/EXEC 事务中的 BLPOP
      • BRPOP
        • 示例
      • LLEN
        • 示例
      • LRANGE
        • 注意 LRANGE 命令和编程语言区间函数的区别
        • 超出范围的下标
        • 示例
      • LREM
        • 示例
      • LSET
        • 示例
      • LTRIM
        • 注意 LTRIM 命令和编程语言区间函数的区别
        • 超出范围的下标
        • 示例
      • LINDEX
        • 示例
      • LINSERT
        • 示例
      • RPOPLPUSH
        • 示例
        • 应用1:安全的队列
        • 应用2:循环列表
      • BRPOPLPUSH
        • 示例
        • 应用1:安全队列
        • 应用2:循环列表

List类型介绍

  • 单键多值:Redis 列表是简单的字符串列表,按照插⼊顺序排序。
  • 你可以添加⼀个元素到列表的头部(左边)或者尾部(右边)。
  • 它的底层实际是个双向链表,对两端的操作性能很⾼,通过索引下标的操作中间的节点性能会较差。
  • Redis 中列表(List)类型是用来存储多个有序的字符串,列表中的每个字符串成为元素Eelement),一个列表最多可以存储 2^32-1 个元素。
  • 在 Redis 中,可以对列表两端插入(push)和弹出(pop),还可以获取指定范围的元素列表、获取指定索引下标的元素等。列表是一种比较灵活的数据结构,可以充当栈和队列的角色,在实际开发中有很多应用场景。

特点

  • 列表中的元素是有序的,即可以通过索引下标获取某个元素或者某个范围内的元素列表;
  • 列表中的元素可以是重复的
    在这里插入图片描述

List数据结构

  • Redis3.2 版本开始,List 类型数据使用的底层数据结构是快速链表,快速列表是以压缩列表为节点的双向链表,将双向链表按段切分,每一段使用压缩列表进行内存的连续存储,多个压缩列表通过 prev 和 next 指针组成的双向链。

  • ⾸先在列表元素较少的情况下会使⽤⼀块连续的内存存储,这个结构是 ziplist,也即是压缩列表。它将所有的元素紧挨着⼀起存储,分配的是⼀块连续的内存。

  • 当数据量⽐较多的时候才会改成 quicklist。因为普通的链表需要的附加指针空间太⼤,会⽐较浪费空间。⽐如这个列表⾥存的只是 int 类型的数据,结构上还需要两个额外的指针 prev 和 next。
    在这里插入图片描述

  • Redis 将链表和 ziplist 结合起来组成了 quicklist。也就是将多个 ziplist 使⽤双向指针串起来使⽤。这样既满⾜了快速的插⼊删除性能,⼜不会出现太⼤的空间冗余。

在这里插入图片描述
考虑到链表的以上缺点,Redis 后续版本对列表数据结构进行改造,使用 QucikList 代替了 ZipList 和 LinkedList。 作为 ZipList 和 LinkedList 的混合体,它将 LinkedList 按段切分,每一段使用 ZipList 来紧凑存储,多个 ZipList 之间使用双向指针串接起来。

附:3.2以前的版本(介绍一下压缩列表和双向链表)

压缩列表ZipList

  • 压缩列表是一块连续的内存空间 (像内存连续的数组,但每个元素长度不同),一个 ziplist 可以包含多个节点(entry)。元素之间紧挨着存储,没有任何冗余空隙。
    在这里插入图片描述
  • 压缩列表的本质就是一个数组,只不过是增加了 “列表长度”、“尾部偏移量”、“列表元素个数” 以及 “列表结束标识”,这样的话就有利于快速的寻找列表的首、尾节点.压缩列表将表中每一项存放在前后连续的地址空间内,每一项因占用的空间不同,而采用变长编码。由于内存是连续分配的,所以遍历速度很快。
  • 当我们的 List 列表数据量比较少的时候,且存储的数据轻量的(如小整数值、短字符串)时候, Redis 就会通过压缩列表来进行底层实现。

双向链表LinkedList

  • LinkedList 是标准的双向链表,Node 节点包含 prev 和 next 指针,分别指向后继与前驱节点,因此从双向链表中的任意一个节点开始都可以很方便地访问其前驱与后继节点。
    在这里插入图片描述

  • LinkedList 可以进行双向遍历;添加删除元素快 O(1),查找元素慢 O(n),高效实现了 LPUSH 、RPOP、RPOPLPUSH,但由于需要为每个节点分配额外的内存空间,所以会浪费一定的内存空间。这种编码方式适用于元素数量较多或者元素较大的场景。

  • LinkedList 结构为链表提供了表头指针 head、表尾指针 tail,以及节点数量计算 len。下图展示一个由 list 结构和三个 listNode 节点组成的链表:
    在这里插入图片描述

  • Redis 的链表实现的特性可以总结如下:

    • 双端:链表节点带有 prev 和 next 指针,获取某个节点的前一节点和后一节点的复杂度都是 O(1);
    • 无环:表头节点的 prev 指针和表尾节点的 next 指针都指向 NULL,对链表的访问以 NULL 为终点;
    • 表头指针/表尾指针:通过 list 结构的 head 指针和 tail 指针,获取链表的表头节点和表尾节点的复杂度为 O(1);
    • 链表长度计数器:通过 list 结构的 len 属性来对 list 的链表节点进行计数,获取节点数量的复杂度为O(1);
    • 多态:链表节点使用 void* 指针来保存节点值,并通过 list 结构的 dup、free、match 三个属性为节点值设置类型特定函数,所以链表可以用于保存各种不同类型的值。
    • 使用链表的附加空间相对太高,因为 64bit 系统中指针是 8 个字节,所以 prev 和 next 指针需要占据 16 个字节,且链表节点在内存中单独分配,会加剧内存的碎片化,影响内存管理效率

常用命令

  • lpush/rpush <key><value1><value2><value3> … 从左边/右边插⼊⼀个或多个值。
  • lpop/rpop <key> 从左边/右边吐出⼀个值。值在键在,值光键亡。
  • rpoplpush <key1><key2> 从 <key1> 列表右边吐出⼀个值,插到 <key2> 列表左边。
  • lrange <key><start><stop> 按照索引下标获得元素(从左到右)
  • lrange mylist 0 -1 0左边第⼀个,-1右边第⼀个,(0-1表示获取所有)
  • lindex <key><index> 按照索引下标获得元素(从左到右)
  • llen <key> 获得列表⻓度
  • linsert <key> before <value><newvalue> 在 <value> 的后⾯插⼊值 <newvalue>
  • lrem <key><n><value> 从左边删除 n 个 value (从左到右)
  • lset <key><index><value> 将列表 key 下标为 index 的值替换成 value

lpush

  • 语法:lpush key value [value …]
  • 解释:
    • 将一个或多个值 value 插入到列表 key 的表头
    • 如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表头:比如说,对空列表 mylist 执行命令 LPUSH mylist a b c ,列表的值将是 c b a ,这等同于原子性地执行 LPUSH mylist a 、 LPUSH mylist b 和 LPUSH mylist c 三个命令。
    • 如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。
    • 当 key 存在但不是列表类型时,返回一个错误。
    • 注: 在 Redis 2.4 版本以前的 LPUSH 命令,都只接受单个 value 值。
  • 时间复杂度:O(1)
  • 返回值:执行 LPUSH 命令后,列表的长度。
示例
# 加入单个元素
127.0.0.1:6379[3]> LPUSH languages python
(integer) 1
# 加入重复元素
127.0.0.1:6379[3]> LPUSH languages python
(integer) 2
127.0.0.1:6379[3]> LRANGE languages 0 -1 # 列表允许重复元素
1) "python"
2) "python"
# 加入多个元素
127.0.0.1:6379[3]> LPUSH mylist a b c
(integer) 3
127.0.0.1:6379[3]> LRANGE mylist 0 -1
1) "c"
2) "b"
3) "a"

lpushx

  • 语法:lpushx key value
  • 解释:
    • 将值 value 插入到列表 key 的表头,当且仅当 key 存在并且是一个列表。
    • 和 LPUSH 命令相反,当 key 不存在时, LPUSHX 命令什么也不做
  • 时间复杂度:O(1)
  • 返回值:LPUSHX 命令执行之后,表的长度
示例
# 对空列表执行 LPUSHX
127.0.0.1:6379[3]> LLEN greet # greet 是一个空列表
(integer) 0
127.0.0.1:6379[3]> LPUSHX greet "hello" # 尝试 LPUSHX,失败,因为列表为空
(integer) 0
# 对非空列表执行 LPUSHX
127.0.0.1:6379[3]> LPUSH greet "hello" # 先用 LPUSH 创建一个有一个元素的列表
(integer) 1
127.0.0.1:6379[3]> LPUSHX greet "good morning" # 这次 LPUSHX 执行成功
(integer) 2
127.0.0.1:6379[3]> LRANGE greet 0 -1
1) "good morning"
2) "hello"

rpush

  • 语法:rpush key value [value …]
  • 解释:
    • 将一个或多个值 value 插入到列表 key 的表尾(最右边)。
    • 如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表尾:比如对一个空列表 mylist 执行 RPUSH mylist a b c ,得出的结果列表为 a b c ,等同于执行命令 RPUSH mylist a RPUSH mylist b RPUSH mylist c
    • 如果 key 不存在,一个空列表会被创建并执行 RPUSH 操作。
    • 当 key 存在但不是列表类型时,返回一个错误。
    • 注:在 Redis 2.4 版本以前的 RPUSH 命令,都只接受单个 value 值。
  • 时间复杂度:O(1)
  • 返回值:执行 RPUSH 操作后,表的长度。
示例
# 添加单个元素
127.0.0.1:6379[3]> RPUSH languages c
(integer) 1
# 添加重复元素
127.0.0.1:6379[3]> RPUSH languages c
(integer) 2
127.0.0.1:6379[3]> LRANGE languages 0 -1 # 列表允许重复元素
1) "c"
2) "c"
# 添加多个元素
127.0.0.1:6379[3]> RPUSH mylist a b c
(integer) 3
127.0.0.1:6379[3]> LRANGE mylist 0 -1
1) "a"
2) "b"
3) "c"

rpushx

  • 语法:rpushx key value
  • 解释:
    • 将值 value 插入到列表 key 的表尾,当且仅当 key 存在并且是一个列表。
    • 和 RPUSH 命令相反,当 key 不存在时, RPUSHX 命令什么也不做。
  • 时间复杂度:O(1)
  • 返回值:RPUSHX 命令执行之后,表的长度
示例
# key 不存在
127.0.0.1:6379[3]> LLEN greet
(integer) 0
127.0.0.1:6379[3]> RPUSHX greet "hello" # 对不存在的 key 进行 RPUSHX,PUSH 失败。
(integer) 0
# key 存在且是一个非空列表
127.0.0.1:6379[3]> RPUSH greet "hi" # 先用 RPUSH 插入一个元素
(integer) 1
127.0.0.1:6379[3]> RPUSHX greet "hello" # greet 现在是一个列表类型,RPUSHX 操作
成功。
(integer) 2
127.0.0.1:6379[3]> LRANGE greet 0 -1
1) "hi"
2) "hello"

LPOP

  • 语法:lpop key
  • 解释:移除并返回列表 key 的头元素。
  • 时间复杂度: O(1)
  • 返回值:
    • 列表的头元素。
    • 当 key 不存在时,返回 nil 。
示例
127.0.0.1:6379[3]> LLEN course
(integer) 0
127.0.0.1:6379[3]> RPUSH course algorithm001
(integer) 1
127.0.0.1:6379[3]> RPUSH course c++101
(integer) 2
127.0.0.1:6379[3]> LPOP course # 移除头元素
"algorithm001"

RPOP

  • 语法:rpop key
  • 解释:移除并返回列表 key 的尾元素。
  • 时间复杂度: O(1)
  • 返回值:
    • 列表的尾元素。
    • 当 key 不存在时,返回 nil 。
示例
127.0.0.1:6379[3]> RPUSH mylist "one"
(integer) 1
127.0.0.1:6379[3]> RPUSH mylist "two"
(integer) 2
127.0.0.1:6379[3]> RPUSH mylist "three"
(integer) 3
127.0.0.1:6379[3]> RPOP mylist # 返回被弹出的元素
"three"
127.0.0.1:6379[3]> LRANGE mylist 0 -1 # 列表剩下的元素
1) "one"
2) "two"

BLPOP

  • 语法:blpop key [key …] timeout
  • 解释:
    • BLPOP 是列表的阻塞式(blocking)弹出原语。
    • 它是 LPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被BLPOP 命令阻塞,直到等待超时或发现可弹出元素为止。
    • 当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。
非阻塞行为
  • 当 BLPOP 被调用时,如果给定 key 内至少有一个非空列表,那么弹出遇到的第一个非空列表的头元素,并和被弹出元素所属的列表的名字一起,组成结果返回给调用者。

  • 当存在多个给定 key 时, BLPOP 按给定 key 参数排列的先后顺序,依次检查各个列表。

  • 假设现在有 job 、 command 和 request 三个列表,其中 job 不存在, command 和request 都持有非空列表。考虑以下命令:BLPOP job command request 0

  • BLPOP 保证返回的元素来自 command ,因为它是按”查找 job -> 查找 command -> 查找 request “这样的顺序,第一个找到的非空列表。

    127.0.0.1:6379[3]> DEL job command request # 确保 key 都被删除
    (integer) 0
    127.0.0.1:6379[3]> LPUSH command "update system..." # 为 command 列表增加一个值
    (integer) 1
    127.0.0.1:6379[3]> LPUSH request "visit page" # 为 request 列表增加一个值
    (integer) 1
    127.0.0.1:6379[3]> BLPOP job command request 0 # job 列表为空,被跳过,紧接着command 列表的第一个元素被弹出。
    1) "command" # 弹出元素所属的列表
    2) "update system..." # 弹出元素所属的值
    
阻塞行为
  • 如果所有给定 key 都不存在或包含空列表,那么 BLPOP 命令将阻塞连接,直到等待超时,或有另一个客户端对给定 key 的任意一个执行 LPUSH 或 RPUSH 命令为止。

  • 超时参数 timeout 接受一个以秒为单位的数字作为值。超时参数设为 0 表示阻塞时间可以无限期延长(block indefinitely) 。

    127.0.0.1:6379[3]> EXISTS job # 确保两个 key 都不存在
    (integer) 0
    127.0.0.1:6379[3]> EXISTS command
    (integer) 0
    127.0.0.1:6379[3]> BLPOP job command 300 # 因为 key 一开始不存在,所以操作会被阻塞,直到另一客户端对 job 或者 command 列表进行 PUSH 操作。
    1) "job" # 这里被 push 的是 job
    2) "do my home work" # 被弹出的值
    (26.26s) # 等待的秒数
    127.0.0.1:6379[3]> BLPOP job command 5 # 等待超时的情况
    (nil)
    (5.66s) # 等待的秒数
    
相同的 key 被多个客户端同时阻塞
  • 相同的 key 可以被多个客户端同时阻塞。
  • 不同的客户端被放进一个队列中,按『先阻塞先服务』(first-BLPOP,first-served)的顺序为 key 执行 BLPOP 命令。
在 MULTI/EXEC 事务中的 BLPOP
  • BLPOP 可以用于流水线(pipline,批量地发送多个命令并读入多个回复),但把它用在MULTI / EXEC 块当中没有意义。因为这要求整个服务器被阻塞以保证块执行时的原子性,该行为阻止了其他客户端执行 LPUSH 或 RPUSH 命令。

  • 因此,一个被包裹在 MULTI / EXEC 块内的 BLPOP 命令,行为表现得就像 LPOP 一样,对空列表返回 nil ,对非空列表弹出列表元素,不进行任何阻塞操作。

    # 对非空列表进行操作
    127.0.0.1:6379[3]> RPUSH job programming
    (integer) 1
    127.0.0.1:6379[3]> MULTI
    OK
    127.0.0.1:6379[3]> BLPOP job 30
    QUEUED
    127.0.0.1:6379[3]> EXEC # 不阻塞,立即返回1) "job"2) "programming"
    # 对空列表进行操作
    127.0.0.1:6379[3]> LLEN job # 空列表
    (integer) 0
    127.0.0.1:6379[3]> MULTI
    OK
    127.0.0.1:6379[3]> BLPOP job 30
    QUEUED
    127.0.0.1:6379[3]> EXEC # 不阻塞,立即返回
    1) (nil)
    
  • 时间复杂度: O(1)

  • 返回值:

    • 如果列表为空,返回一个 nil 。
    • 否则,返回一个含有两个元素的列表,第一个元素是被弹出元素所属的 key ,第二个元素是被弹出元素的值

BRPOP

  • 语法:brpop key [key …] timeout
  • 解释:
    • BRPOP 是列表的阻塞式(blocking)弹出原语。
    • 它是 RPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被BRPOP 命令阻塞,直到等待超时或发现可弹出元素为止。
    • 当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的尾部元素。
    • 关于阻塞操作的更多信息,请查看 BLPOP 命令, BRPOP 除了弹出元素的位置和 BLPOP 不同之外,其他表现一致。
  • 时间复杂度:O(1)
  • 返回值:
    • 假如在指定时间内没有任何元素被弹出,则返回一个 nil 和等待时长。
    • 反之,返回一个含有两个元素的列表,第一个元素是被弹出元素所属的 key ,第二个元素是被弹出元素的值。
示例
127.0.0.1:6379[3]> LLEN course
(integer) 0
127.0.0.1:6379[3]> RPUSH course algorithm001
(integer) 1
127.0.0.1:6379[3]> RPUSH course c++101
(integer) 2
127.0.0.1:6379[3]> BRPOP course 30
1) "course" # 弹出元素的 key
2) "c++101" # 弹出元素的值

LLEN

  • 语法:llen key
  • 解释:
    • 返回列表 key 的长度。
    • 如果 key 不存在,则 key 被解释为一个空列表,返回 0 .
    • 如果 key 不是列表类型,返回一个错误。
  • 时间复杂度:O(1)
  • 返回值:列表 key 的长度。
示例
# 空列表
127.0.0.1:6379[3]> LLEN job
(integer) 0
# 非空列表
127.0.0.1:6379[3]> LPUSH job "cook food"
(integer) 1
127.0.0.1:6379[3]> LPUSH job "have lunch"
(integer) 2
127.0.0.1:6379[3]> LLEN job
(integer) 2

LRANGE

  • 语法:lrange key start stop
  • 解释:
    • 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。
    • 下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
    • 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
注意 LRANGE 命令和编程语言区间函数的区别
  • 假如你有一个包含一百个元素的列表,对该列表执行 LRANGE list 0 10 ,结果是一个包含 11 个元素的列表,这表明 stop 下标也在 LRANGE 命令的取值范围之内(闭区间),这和某些语言的区间函数可能不一致,比如 Ruby 的 Range.new 、 Array#slice 和 Python的 range() 函数。
超出范围的下标
  • 超出范围的下标值不会引起错误。
  • 如果 start 下标比列表的最大下标 end ( LLEN list 减去 1 )还要大,或者 start > stop , LRANGE 返回一个空列表。
  • 如果 stop 下标比 end 下标还要大,Redis 将 stop 的值设置为 end 。
  • 时间复杂度:O(S+N), S 为偏移量 start , N 为指定区间内元素的数量。
  • 返回值:一个列表,包含指定区间内的元素。
示例
# 空列表
127.0.0.1:6379[3]> RPUSH fp-language lisp
(integer) 1
127.0.0.1:6379[3]> LRANGE fp-language 0 0
1) "lisp"
127.0.0.1:6379[3]> RPUSH fp-language scheme
(integer) 2
127.0.0.1:6379[3]> LRANGE fp-language 0 1
1) "lisp"
2) "scheme"

LREM

  • 语法:lrem key count value
  • 解释:
    • 根据参数 count 的值,移除列表中与参数 value 相等的元素。
    • count 的值可以是以下几种:
      • count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
      • count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
      • count = 0 : 移除表中所有与 value 相等的值。
  • 时间复杂度:O(N), N 为列表的长度。
  • 返回值:被移除元素的数量。因为不存在的 key 被视作空表(empty list),所以当 key 不存在时, LREM 命令总是返回 0 。
示例
# 空列表
# 先创建一个表,内容排列是
# morning hello morning helllo morning
127.0.0.1:6379[3]> LPUSH greet "morning"
(integer) 1
127.0.0.1:6379[3]> LPUSH greet "hello"
(integer) 2
127.0.0.1:6379[3]> LPUSH greet "morning"
(integer) 3
127.0.0.1:6379[3]> LPUSH greet "hello"
(integer) 4
127.0.0.1:6379[3]> LPUSH greet "morning"
(integer) 5
127.0.0.1:6379[3]> LRANGE greet 0 4 # 查看所有元素
1) "morning"
2) "hello"
3) "morning"
4) "hello"
5) "morning"
127.0.0.1:6379[3]> LREM greet 2 morning # 移除从表头到表尾,最先发现的两个 morning
(integer) 2 # 两个元素被移除
127.0.0.1:6379[3]> LLEN greet # 还剩 3 个元素
(integer) 3
127.0.0.1:6379[3]> LRANGE greet 0 2
1) "hello"
2) "hello"
3) "morning"
127.0.0.1:6379[3]> LREM greet -1 morning # 移除从表尾到表头,第一个 morning
(integer) 1
127.0.0.1:6379[3]> LLEN greet # 剩下两个元素
(integer) 2
127.0.0.1:6379[3]> LRANGE greet 0 1
1) "hello"
2) "hello"
127.0.0.1:6379[3]> LREM greet 0 hello # 移除表中所有 hello
(integer) 2 # 两个 hello 被移除
127.0.0.1:6379[3]> LLEN greet
(integer) 0

LSET

  • 语法:lset key index value
  • 解释:
    • 将列表 key 下标为 index 的元素的值设置为 value 。
    • 当 index 参数超出范围,或对一个空列表( key 不存在)进行 LSET 时,返回一个错误。
    • 关于列表下标的更多信息,请参考 LINDEX 命令。
  • 时间复杂度:对头元素或尾元素进行 LSET 操作,复杂度为 O(1)。其他情况下,为 O(N), N 为列表的长度。
  • 返回值:操作成功返回 ok ,否则返回错误信息。
示例
# 对空列表(key 不存在)进行 LSET
127.0.0.1:6379[3]> EXISTS list
(integer) 0
127.0.0.1:6379[3]> LSET list 0 item
(error) ERR no such key
# 对非空列表进行 LSET
127.0.0.1:6379[3]> LPUSH job "cook food"
(integer) 1
127.0.0.1:6379[3]> LRANGE job 0 0
1) "cook food"
127.0.0.1:6379[3]> LSET job 0 "play game"
OK
127.0.0.1:6379[3]> LRANGE job 0 0
1) "play game"
# index 超出范围
127.0.0.1:6379[3]> LLEN list # 列表长度为 1
(integer) 1
127.0.0.1:6379[3]> LSET list 3 'out of range'
(error) ERR index out of range

LTRIM

  • 语法:ltrim key start stop
  • 解释:
    • 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
    • 举个例子,执行命令 LTRIM list 0 2 ,表示只保留列表 list 的前三个元素,其余元素全部删除。
    • 下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
    • 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
    • 当 key 不是列表类型时,返回一个错误。
    • LTRIM 命令通常和 LPUSH 命令或 RPUSH 命令配合使用,举个例子
      LPUSH log newest_log
      LTRIM log 0 99
      
    • 这个例子模拟了一个日志程序,每次将最新日志 newest_log 放到 log 列表中,并且只保留最新的 100 项。注意当这样使用 LTRIM 命令时,时间复杂度是 O(1),因为平均情况下,每次只有一个元素被移除。
注意 LTRIM 命令和编程语言区间函数的区别
  • 假如你有一个包含一百个元素的列表 list ,对该列表执行 LTRIM list 0 10 ,结果是一个包含 11 个元素的列表,这表明 stop 下标也在 LTRIM 命令的取值范围之内(闭区间),这和某些语言的区间函数可能不一致,比如 Ruby 的 Range.new 、 Array#slice 和 Python的 range() 函数。
超出范围的下标
  • 超出范围的下标值不会引起错误。

  • 如果 start 下标比列表的最大下标 end ( LLEN list 减去 1 )还要大,或者 start > stop , LTRIM 返回一个空列表(因为 LTRIM 已经将整个列表清空)。

  • 如果 stop 下标比 end 下标还要大,Redis 将 stop 的值设置为 end 。

  • 时间复杂度:O(N), N 为被移除的元素的数量。

  • 返回值:命令执行成功时,返回 ok 。

示例
# 一般情况下标
127.0.0.1:6379[3]> LRANGE alpha 0 -1 # 建立一个 5 元素的列表
1) "h"
2) "e"
3) "l"
4) "l"
5) "o"
127.0.0.1:6379[3]> LTRIM alpha 1 -1 # 删除索引为 0 的元素
OK
127.0.0.1:6379[3]> LRANGE alpha 0 -1 # "h" 被删除
1) "e"
2) "l"
3) "l"
4) "o"
# stop 下标比元素的最大下标要大
127.0.0.1:6379[3]> LTRIM alpha 1 10086
OK
127.0.0.1:6379[3]> LRANGE alpha 0 -1
1) "l"
2) "l"
3) "o"
# start 和 stop 下标都比最大下标要大,且 start < sotp
127.0.0.1:6379[3]> LTRIM alpha 10086 200000
OK
127.0.0.1:6379[3]> LRANGE alpha 0 -1 # 整个列表被清空,等同于 DEL alpha
(empty list or set)
# start > stop
127.0.0.1:6379[3]> LRANGE alpha 0 -1 # 在新建一个列表
1) "h"
2) "u"
3) "a"
4) "n"
5) "g"
6) "z"
127.0.0.1:6379[3]> LTRIM alpha 10086 4
OK
127.0.0.1:6379[3]> LRANGE alpha 0 -1 # 列表同样被清空
(empty list or set)

LINDEX

  • 语法:lindex key index
  • 解释:
    • 返回列表 key 中,下标为 index 的元素。
    • 下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
    • 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
    • 如果 key 不是列表类型,返回一个错误。
  • 时间复杂度:
    • O(N), N 为到达下标 index 过程中经过的元素数量。
    • 因此,对列表的头元素和尾元素执行 LINDEX 命令,复杂度为 O(1)。
  • 返回值:
    • 列表中下标为 index 的元素。
    • 如果 index 参数的值不在列表的区间范围内(out of range),返回 nil 。
示例
127.0.0.1:6379[3]> LPUSH mylist "World"
(integer) 1
127.0.0.1:6379[3]> LPUSH mylist "Hello"
(integer) 2
127.0.0.1:6379[3]> LINDEX mylist 0
"Hello"
127.0.0.1:6379[3]> LINDEX mylist -1
"World"
127.0.0.1:6379[3]> LINDEX mylist 3 # index 不在 mylist 的区间范围内
(nil)

LINSERT

  • 语法:linsert key BEFORE|AFTER pivot value
  • 解释:
    • 将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。
    • 当 pivot 不存在于列表 key 时,不执行任何操作。
    • 当 key 不存在时, key 被视为空列表,不执行任何操作。
    • 如果 key 不是列表类型,返回一个错误。
  • 时间复杂度:O(N), N 为寻找 pivot 过程中经过的元素数量。
  • 返回值:
    • 如果命令执行成功,返回插入操作完成之后,列表的长度。
    • 如果没有找到 pivot ,返回 -1 。
    • 如果 key 不存在或为空列表,返回 0
示例
127.0.0.1:6379[3]> RPUSH mylist "Hello"
(integer) 1
127.0.0.1:6379[3]> RPUSH mylist "World"
(integer) 2
127.0.0.1:6379[3]> LINSERT mylist BEFORE "World" "There"
(integer) 3
127.0.0.1:6379[3]> LRANGE mylist 0 -1
1) "Hello"
2) "There"
3) "World"
# 对一个非空列表插入,查找一个不存在的 pivot
127.0.0.1:6379[3]> LINSERT mylist BEFORE "go" "let's"
(integer) -1 # 失败
# 对一个空列表执行 LINSERT 命令
127.0.0.1:6379[3]> EXISTS fake_list
(integer) 0
127.0.0.1:6379[3]> LINSERT fake_list BEFORE "nono" "gogogog"
(integer) 0 # 失败

RPOPLPUSH

  • 语法:rpoplpush source destination
  • 解释:
    • 命令 RPOPLPUSH 在一个原子时间内,执行以下两个动作:
      • 将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。
      • 将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。
    • 举个例子,你有两个列表 source 和 destination , source 列表有元素 a, b, c ,destination 列表有元素 x, y, z ,执行 RPOPLPUSH source destination 之后, source 列表包含元素 a, b , destination 列表包含元素 c, x, y, z ,并且元素 c 会被返回给客户端。
      • 如果 source 不存在,值 nil 被返回,并且不执行其他动作。
      • 如果 source 和 destination 相同,则列表中的表尾元素被移动到表头,并返回该元素,可以把这种特殊情况视作列表的旋转(rotation)操作。
  • 时间复杂度:O(1)
  • 返回值:被弹出的元素。
示例
# source 和 destination 不同
127.0.0.1:6379[3]> LRANGE alpha 0 -1 # 查看所有元素
1) "a"
2) "b"
3) "c"
4) "d"
127.0.0.1:6379[3]> RPOPLPUSH alpha reciver # 执行一次 RPOPLPUSH 看看
"d"
127.0.0.1:6379[3]> LRANGE alpha 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379[3]> LRANGE reciver 0 -1
1) "d"
127.0.0.1:6379[3]> RPOPLPUSH alpha reciver # 再执行一次,证实 RPOP 和 LPUSH 的位置正确
"c"
127.0.0.1:6379[3]> LRANGE alpha 0 -1
1) "a"
2) "b"
127.0.0.1:6379[3]> LRANGE reciver 0 -1
1) "c"
2) "d"
# source 和 destination 相同
127.0.0.1:6379[3]> LRANGE number 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379[3]> RPOPLPUSH number number
"4"
127.0.0.1:6379[3]> LRANGE number 0 -1 # 4 被旋转到了表头
1) "4"
2) "1"
3) "2"
4) "3"
127.0.0.1:6379[3]> RPOPLPUSH number number
"3"
127.0.0.1:6379[3]> LRANGE number 0 -1 # 这次是 3 被旋转到了表头
1) "3"
2) "4"
3) "1"
4) "2"
应用1:安全的队列
  • Redis 的列表经常被用作队列(queue),用于在不同程序之间有序地交换消息(message)。一个客户端通过 LPUSH 命令将消息放入队列中,而另一个客户端通过 RPOP 或者 BRPOP 命令取出队列中等待时间最长的消息。
  • 不幸的是,上面的队列方法是『不安全』的,因为在这个过程中,一个客户端可能在取出一个消息之后崩溃,而未处理完的消息也就因此丢失。
  • 使用 RPOPLPUSH 命令(或者它的阻塞版本 BRPOPLPUSH )可以解决这个问题:因为它不仅返回一个消息,同时还将这个消息添加到另一个备份列表当中,如果一切正常的话,当一个客户端完成某个消息的处理之后,可以用 LREM 命令将这个消息从备份表删除。
  • 最后,还可以添加一个客户端专门用于监视备份表,它自动地将超过一定处理时限的消息重新放入队列中去(负责处理该消息的客户端可能已经崩溃),这样就不会丢失任何消息了。
应用2:循环列表
  • 通过使用相同的 key 作为 RPOPLPUSH 命令的两个参数,客户端可以用一个接一个地获取列表元素的方式,取得列表的所有元素,而不必像 LRANGE 命令那样一下子将所有列表元素都从服务器传送到客户端中(两种方式的总复杂度都是 O(N))。
  • 以上的模式甚至在以下的两个情况下也能正常工作:
    • 有多个客户端同时对同一个列表进行旋转(rotating),它们获取不同的元素,直到所有元素都被读取完,之后又从头开始。
    • 有客户端在向列表尾部(右边)添加新元素。
  • 这个模式使得我们可以很容易实现这样一类系统:有 N 个客户端,需要连续不断地对一些元素进行处理,而且处理的过程必须尽可能地快。一个典型的例子就是服务器的监控程序:
    • 它们需要在尽可能短的时间内,并行地检查一组网站,确保它们的可访问性。
  • 注意,使用这个模式的客户端是易于扩展(scala)且安全(reliable)的,因为就算接收到元素的客户端失败,元素还是保存在列表里面,不会丢失,等到下个迭代来临的时候,别的客户端又可以继续处理这些元素了。

BRPOPLPUSH

  • 语法:brpoplpush source destination timeout
  • 解释:
    • BRPOPLPUSH 是 RPOPLPUSH 的阻塞版本,当给定列表 source 不为空时, BRPOPLPUSH的表现和 RPOPLPUSH 一样。
    • 当列表 source 为空时, BRPOPLPUSH 命令将阻塞连接,直到等待超时,或有另一个客户端对 source 执行 LPUSH 或 RPUSH 命令为止。
    • 超时参数 timeout 接受一个以秒为单位的数字作为值。超时参数设为 0 表示阻塞时间可以无限期延长(block indefinitely) 。
    • 更多相关信息,请参考 RPOPLPUSH 命令。
  • 时间复杂度:O(1)
  • 返回值:
    • 假如在指定时间内没有任何元素被弹出,则返回一个 nil 和等待时长。
    • 反之,返回一个含有两个元素的列表,第一个元素是被弹出元素的值,第二个元素是等待时长。
示例
# 非空列表
127.0.0.1:6379[3]> BRPOPLPUSH msg reciver 500
"hello moto" # 弹出元素的值
(3.38s) # 等待时长
127.0.0.1:6379[3]> LLEN reciver
(integer) 1
127.0.0.1:6379[3]> LRANGE reciver 0 0
1) "hello moto"
# 空列表
127.0.0.1:6379[3]> BRPOPLPUSH msg reciver 1
(nil)
(1.34s)
应用1:安全队列

参考 RPOPLPUSH 命令的『安全队列』模式。

应用2:循环列表

参考 RPOPLPUSH 命令的『循环列表』模式

相关文章:

【redis】Redis数据类型(三)List类型

目录 List类型介绍特点 List数据结构附&#xff1a;3.2以前的版本(介绍一下压缩列表和双向链表)压缩列表ZipList双向链表LinkedList 常用命令lpush示例 lpushx示例 rpush示例 rpushx示例 LPOP示例 RPOP示例 BLPOP非阻塞行为阻塞行为相同的 key 被多个客户端同时阻塞在 MULTI/EX…...

Java面试题:多线程2

如何停止正在运行的线程 1,使用退出标志,使线程正常退出(run方法中循环对退出标志进行判断) 2,使用stop()方法强行终止(不推荐) 3,调用interrupt()方法中断线程 打断阻塞线程(sleep,wait,join),线程会抛出InterruptedException异常 打断正常的线程,可以根据打断状态来标记…...

T型槽地轨承载力是如何连接整个制造过程的强力桥梁(北重公司设计)

T型槽地轨承载力的定义和计算 T型槽地轨是一种用于工业设备运输和装配的关键组件。它由世界上各行各业的生产商广泛采用&#xff0c;其有效的承载力使其成为连接整个制造过程的强力桥梁。本文将介绍T型槽地轨的承载力以及相关的设计要点和应用。 承载力的定义和计算 承载力是…...

【Numpy】一文向您详细介绍 np.linspace()

【Numpy】一文向您详细介绍 np.linspace() &#x1f308; 欢迎莅临我的个人主页&#x1f448; 这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1a;985高校的计算机专业人士&#xff0c;热衷于分享技术见…...

VMware虚拟网卡网络适配器出现黄色感叹号

问题发生&#xff1a;VMware在使用Ubuntu的过程中突然卡死&#xff0c;强制关闭开启后就发生了网络无法连接 找到电脑的设备管理发现VMware的适配器出现黄色感叹号 解决方法&#xff1a; 下载软件ccleaner 扫描问题&#xff0c;懒得去找就修复了所有的问题 最后发现适配器…...

论生命价值

我们该如何定义一个人的生命价值&#xff0c;这是一个十分值得我们深思的问题&#xff0c;而谈论到生命的价值&#xff0c;我们先从非人的东西去谈论它的价值&#xff0c;从我们作为人的角度去思考价值&#xff0c;一个东西对我们有用&#xff0c;这个东西能够让我们的主观上的…...

基于Springboot的民航网上订票系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的民航网上订票系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…...

ubuntu开启message文件

环境&#xff1a;ubuntu 20.04 1、首先需要修改 /etc/rsyslog.d/50-default.conf 文件&#xff1b;源文件中message被注释&#xff0c;如下图&#xff1a; 2、打开注释&#xff1a; 3、重启服务 systemctl restart rsyslog.service 如此即可&#xff01;...

ISIS的基本概念

1.ISIS概述 IS-IS是一种链路状态路由协议&#xff0c;IS-IS与OSPF在许多方面非常相似&#xff0c; 例如运行IS-IS协议的直连设备之间通过发送Hello报文发现彼此&#xff0c;然后建立邻接关系&#xff0c;并交互链路状态信息。 CLNS由以下三个部分组成&#xff1a; CLNP&#xf…...

Vue 工程化开发入门

Vue开发的两种方式&#xff1a; 核心包传统开发模式&#xff1a;基于html/css/js文件&#xff0c;直接引入核心包&#xff0c;开发Vue工程化开发模式&#xff1a;基于构建工具的环境中开发Vue 这里选择Vue cli脚手架 进行开发&#xff0c;搜索教程自行下载。 组件化开发 一个页…...

车牌号识别系统:PyQT5+QT Designe+crnn/PaddleOCR+YOLO+OpenCV矫正算法。

PyQT5&QT Designecrnn/PaddleOCRYOLO传统OpenCV矫正算法。可视化的车牌识别系统项目。 车牌号识别系统 项目绪论1.项目展示2.视频展示3.整体思路 一、PyQT5 和 QT Designer1.简介2.安装3.使用 二、YOLO检测算法三、OpenCV矫正算法四、crnn/PaddleOCR字符识别算法五、QT界面…...

【基于MAX98357的Minimax(百度)长文本语音合成TTS 接入教程】

【基于MAX98357的Minimax&#xff08;百度&#xff09;长文本语音合成TTS 接入教程】 1. 前言2. 先决条件2.1 硬件准备2.2 软件准备2.3 接线 3. 核心代码3.1 驱动实现3.2 代码解析 4. 播放文本5. 结论 视频地址&#xff1a; SeeedXIAO ESP32S3 Sense【基于MAX98357的Minimax&am…...

秋招后端开发面试题 - JVM底层原理

目录 JVM底层原理前言面试题Java 对象的创建过程&#xff1f;什么是指针碰撞&#xff1f;什么是空闲列表&#xff1f;/ 内存分配的两种方式&#xff1f;JVM 里 new 对象时&#xff0c;堆会发生抢占吗&#xff1f;JVM 是怎么设计来保证线程安全的&#xff1f;/ 内存分配并发问题…...

VUE2从入门到精通(一)

**************************************************************************************************************************************************************************** 1、课程概述 【1】前置储备&#xff1a;HTMLCSSJS、WebAPI、Ajax、Node.js 【2】1天&…...

cmake进阶:文件操作之写文件

一. 简介 cmake 提供了 file() 命令可对文件进行一系列操作&#xff0c;譬如读写文件、删除文件、文件重命名、拷贝文件、创建目录等等。 接下来 学习这个功能强大的 file() 命令。 本文学习 CMakeLists.txt语法中写文件操作。 二. cmake进阶&#xff1a;文件操作之写文件…...

ubuntu 安装单节点HBase

下载HBase mkdir -p /home/ellis/HBase/ cd /home/ellis/HBase/ wget https://downloads.apache.org/hbase/2.5.8/hbase-2.5.8-bin.tar.gz tar -xvf hbase-2.5.8-bin.tar.gz安装java jdk sudo apt install openjdk-11-jdksudo vim /etc/profileexport JAVA_HOME/usr/lib/jvm/…...

HTTP 多个版本

了解一下各个版本的HTTP。 上个世纪90年代初期&#xff0c;蒂姆伯纳斯-李&#xff08;Tim Berners-Lee&#xff09;及其 CERN的团队共同努力&#xff0c;制定了互联网的基础&#xff0c;定义了互联网的四个构建模块&#xff1a; 超文本文档格式&#xff08;HTML&#xff09; …...

【DevOps】探索Linux命令行世界:深入了解Shell的力量

目录 一、Linux Shell 详细介绍 1. Shell基础概念 2. Shell的功能特性 3. 常用Shell命令与技巧 4. 高级Shell特性与实践 二、常见的Shell及其比较 1. Bash (Bourne Again SHell) 2. Zsh (Z Shell) 3. Fish (Friendly Interactive SHell) 4. Ksh (Korn SHell) 5. Csh …...

互斥量的使用

文章目录 前言一、互斥量与二进制信号量二、优先级反转与优先级继承三、递归锁 前言 通过学习上一章互斥量理论基础&#xff0c;这一章我们来做一些实验进行验证。 一、互斥量与二进制信号量 互斥量使用和二进制信号量类似 互斥量有优先级继承功能&#xff0c;二进制信号量没有…...

关于面试真题的压迫

1.请描述一下您在使用JavaScript进行DOM操作时&#xff0c;如何提高页面性能和用户体验&#xff1f; 使用事件委托&#xff1a;在父元素上监听事件&#xff0c;而不是为每个子元素都添加事件监听器。这样可以减少事件处理程序的数量&#xff0c;提高性能。 缓存DOM查询&#x…...

1700java进销存管理系统Myeclipse开发sqlserver数据库web结构java编程计算机网页项目

一、源码特点 java web进销存管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为sqlser…...

mysql数据库(排序与分页)

目录 一. 排序数据 1.1 排序规则 1.2 单列排序 1.我们也可以使用列的别名&#xff0c;给别名进行排序 2.列的别名只能在 ODER BY 中使用&#xff0c; 不能在WHERE中使用。 3.强调格式&#xff1a;WHERE 需要在 FROM 后&#xff0c; ORDER BY 之前 1.3 二级排序&…...

Android 实时监听Activity堆栈变化(系统应用)

private val mIActivityManager: IActivityManager ActivityManagerNative.asInterface(ServiceManager.getService(Context.ACTIVITY_SERVICE)) 方式一&#xff08;registerProcessObserver&#xff09; &#xff1a; mIActivityManager.registerProcessObserver(mIProcess…...

双目深度估计原理立体视觉

双目深度估计原理&立体视觉 0. 写在前面1. 双目估计的大致步骤2. 理想双目系统的深度估计公式推导3. 双目标定公式推导4. 极线校正理论推导 0. 写在前面 双目深度估计是通过两个相机的对同一个点的视差来得到给该点的深度。 标准系统的双目深度估计的公式推导需要满足:1)两…...

Redis探索之旅(基础)

目录 今日良言&#xff1a;满怀憧憬&#xff0c;阔步向前 一、基础命令 1.1 通用命令 1.2 五大基本类型的命令 1.2.1 String 1.2.2 Hash 1.2.3 List 1.2.4 Set 1.2.5 Zset 二、过期策略以及单线程模型 2.1 过期策略 2.2 单线程模型 2.3 Redis 效率为什么这么高 三…...

C语言/数据结构——每日一题(链表的中间节点)

一.前言 今天我在LeetCode刷到了一道单链表题&#xff0c;想着和大家分享一下这道题&#xff1a;https://leetcode.cn/problems/middle-of-the-linked-list。废话不多说让我们开始今天的知识分享吧。 二.正文 1.1题目描述 1.2题目分析 这道题有一个非常简便的方法——快慢指…...

这是用VS写的一个tcp客户端和服务端的demo

服务端&#xff1a; 客户端&#xff1a; 其实这里面的核心代码就两行。 客户端的核心代码&#xff1a; //套接字连接服务端 m_tcpSocket->connectToHost(_ip,_port);//通过套接字发送数据m_tcpSocket->write(ui.textEditSend->toPlainText().toUtf8());//如果收到信…...

代码随想录算法训练营day18 | 102.二叉树的层序遍历、226.翻转二叉树、101. 对称二叉树

102.二叉树的层序遍历 迭代法 层序遍历使用队列&#xff0c;同时记录每层的个数 class Solution:def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:res []if not root:return resqueue collections.deque()queue.append(root)while queue:size len…...

工厂自动化升级改造参考(01)--设备通信协议详解及选型

以下是整合了通信协议的特点、应用场景、优缺点以及常用接口方式的描述: 以太网/IP: 来历: 以太网是一种局域网技术,由罗伯特梅特卡夫和大卫博格在1973年开发。IP是网络层协议,负责在网络中的设备间传输数据。特点:基于标准的以太网技术,使用TCP/IP协议栈,支持高速数据传…...

数据结构与算法之经典排序算法

一、简单排序 在我们的程序中&#xff0c;排序是非常常见的一种需求&#xff0c;提供一些数据元素&#xff0c;把这些数据元素按照一定的规则进行排序。比如查询一些订单按照订单的日期进行排序&#xff0c;再比如查询一些商品&#xff0c;按照商品的价格进行排序等等。所以&a…...

wordpress代码加亮的/自学seo能找到工作吗

后续内容参考&#xff1a;php处理数据并连接数据库 https://blog.csdn.net/qwe24111/article/details/99644132 该文只介绍了php接收数据并连接数据库的一般相关操作&#xff0c;可作为后续php程序处理数据的参考 接收esp8266数据可以采用多种方法 方法一&#xff1a;tcp/ip协…...

网站排名推广自己怎么做/50篇经典软文100字

性能优化总结&#xff1a; 1 尽量避免频繁创建对象&#xff0c;即减少&{},new,make的使用2 数组可当切片用&#xff0c;当需要使用切片时&#xff0c;可考虑能使用数组来减少切片的创建3 当某类临时对象被多个协频繁程使用时&#xff0c;可用sync.pool做缓存4 当某类临时对…...

医院网站开发百度文库/互联网运营

目录&#xff1a;...

软件平台包括什么/宁波专业seo外包

这是一篇Python入门指南&#xff0c;针对没有编程经验&#xff0c;甚至从未涉足计算机编程领域的「小白」。 不管你学习的初衷是热爱还是工作、转行需要&#xff0c;都能在这篇内容中找到答案。 Python 作为当下最火的编程语言之一&#xff0c;网上的学习教程很多&#xff0c;不…...

wordpress文章中调用自定义字段/肇庆百度快照优化

一、函数 函数是一种从定义域隐射到值域的特殊的关系&#xff0c;以至于任意自变量对应唯一一个因变量。 因此&#xff0c;&#xff08;对应&#xff09;关系、定义域、值域这三者有至少一个不一样&#xff0c;则代表其函数不一样。 函数的一个输入只能对应唯一的一个输出 二…...

文库网站开发建设/网络营销师报名官网

https://segmentfault.com/a/1190000020934044 引语 最近一段时间在重温ES6&#xff0c;Promise应该是是ES6新特性中非常重要的一部分内容。其实Promise在我日常开发中已经用得比较多&#xff0c;但大多数时候只是知道Promise可以用来实现异步编程&#xff0c;也只限于单纯地…...