前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Mysql参数innodb_thread_concurrency

Mysql参数innodb_thread_concurrency

作者头像
mingjie
发布于 2022-05-12 01:49:32
发布于 2022-05-12 01:49:32
2K00
代码可运行
举报
运行总次数:0
代码可运行

0 长求总

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
innodb_thread_concurrency

- innodb_thread_concurrency是动态参数可以随时修改
- 64个活跃连接以内直接配0
- 高压场景需要从高到低测试,找到最优值
- 高压场景下较低的值可以明显提高写入QPS的占比(高频率的读被限制了)

innodb_thread_sleep_delay(微秒)

- 定义在开始排队前,等多久加入队列

innodb_adaptive_max_sleep_delay(微秒)

- 配置innodb_thread_sleep_delay允许的最大值,配了之后innodb会自动调整innodb_thread_sleep_delay的值到一个合适的范围内(自适应算法)

innodb_concurrency_tickets(默认5000- 使用小的值时小事务可以和大事务竞争,缺点是大事务要多次才能跑完
- 使用大的值时大事务有优势,缺点是可能让小事务一直得不到运行
- 调整这个值可以参考队列长度,长度从SHOW ENGINE INNODB STATUS来看( `ROW OPERATIONS` section of `SHOW ENGINE INNODB STATUS` output),也可以从INFORMATION_SCHEMA.INNODB_TRXTRX_CONCURRENCY_TICKETS来看。

1 官方解释

InnoDB使用操作系统线程来处理用户的事务请求。(在事务提交或回滚之前可能给InnoDB引擎带来很多的请求)。在现代化操作系统和多核处理器的服务器上,上下文切换是非常高效的,大多数工作负载运行没有任何并发线程数量的限制。在MySQL 5.5及以上版本中,MySQL做了可伸缩性的改进,它减少了这种在InnoDB内部限制并发执行线程数量的需要。

它有助于在最小化的情况下进行线程之间的上下文切换,InnoDB可以使用各种技术来限制操作系统并发执行线程的数量(因此大批量的请求可以在任何一个时间得到处理)。当InnoDB从用户会话收到一个新的请求,如果线程并发执行的数量达到预定义的限制,那么新的请求会先睡眠一段时间后再次尝试。在睡眠后不能按计划执行的请求会被放入先入/先出队列,并最终处理。但那些等待获取锁的线程则不会被计入到并发执行线程的数量中。 我们可以通过设置配置参数innodb_thread_concurrency来限制并发线程的数量,一旦执行线程的数量达到这个限制,额外的线程在被放置到对队列中之前,会睡眠数微秒,可以通过设定参数innodb_thread_sleep_delay来配置睡眠时间。

在MySQL 5.6.3及更高版本中,你可以通过设置参数innodb_adaptive_max_sleep_delay为innodb_thread_sleep_delay设置最大允许的值,InnoDB会根据当前线程调度活动自动调整innodb_thread_sleep_delay的值,这种动态调整机制有助于工作的线程,在系统负载低时或系统接近满负荷运转时,都能够顺利的调度。

在MySQL和InnoDB之前的版本系列中,innodb_thread_concurrency的默认值,以及其隐含的限制并发线程执行的数量都进行过调整。在当前最新版本的MySQL中,innodb_thread_concurrency的默认值为0,它表示默认情况下不限制线程并发执行的数量。

另外,InnoDB只有当并发线程数量有限时,线程才会休眠。当线程数量没有限制时,所有这些都同样被安排。也就是说,如果innodb_thread_concurrency是0,值 innodb_thread_sleep_delay被忽略。

当线程数量有限时(当innodb_thread_concurrency>0时),InnoDB通过允许在执行单个SQL语句期间进行的多个请求进入InnoDB而不需要遵守设置的限制 ,从而减少上下文切换开销innodb_thread_concurrency。由于SQL语句(例如join)可能包含多个行操作,所以InnoDB分配指定数量的 “ tickets ”,允许以最少的开销重复排列线程。

当一个新的SQL语句开始,当前线程没有“tickets”时,它就必须遵守innodb_thread_concurrency参数设置,一旦这个线程有权进入InnoDB,它会被分配一个“tickets”,它可以通过这个“tickets”用于随后进入InnoDB执行行操作,如果“tickets”使用完毕,该线程将会被驱逐,innodb_thread_concurrency参数会被放回到先入/先出队列中等待的线程等待再次观察。一旦这个线程再次有权进入InnoDB,“tickets”又会被重新分配,我们可以通过设置全局参数innodb_concurrency_tickets来指定“tickets”的数量,默认情况下是5000。正在等待获取锁的线程,一旦锁可用,会被立即分配一个“tickets”。

这些参数的正确值取决于当前系统环境和负载情况。尝试各种不同的值,以确定哪些值适用于当前应用程序。在限制并发执行的线程数之前,在多核及多处理器的计算机上,检查一下InnoDB的配置参数是否可以改善性能,比如innodb_adaptive_hash_index。

2 野史

innodb_thread_concurrency

innodb_thread_sleep_delay

innodb_concurrency_tickets

这三个参数的配合使用就是这样的一个故事(看网上一个哥们写的,摘抄下来)

一个屋子内有一个头牌妓女叫Innodb,大家都想接近她。

老鸨(MySQL)不可能允许那么多人同时进屋去,就限制每次只能进去几个,这个限制的名字就叫(innodb_thread_concurrency)

其他的人怎么办,只能在外面排成长队依次进入。同时老鸨说,大爷你们可以睡一会,这样就不用苦苦等待了。

这里老鸨就会个一段时间(innodb_thread_sleep_delay)叫醒一位大爷,以免睡不醒了。

老鸨也怕总是叫醒大爷不好交代,就看快到了再叫,老鸨自己发明了一个自适应的叫醒算法,能够尽量减少唤醒次数。但是大爷会规定一个最长唤醒时间,就是必须在这样的时间(innodb_adaptive_max_sleep_delay)时唤醒我。

如此当有人从内部出来以后,等待的大爷(排在最前面的)就可以进入享受鱼水之欢了。

但是每位大爷能够支持的时间不一样,有的一分钟(quicker),有的大爷需要几个小时。这样外面等待的大爷就会有意见,哎呀,怎么还不出来。

老鸨又想了一个办法,规定每个人不能在姑娘房里呆10分钟以上(innodb_concurrency_tickets),有特别持久的人就需要在10分钟时出来,在继续排队(排在队尾)。

等到下一次轮到他再进行鱼水之欢。

人物对应:老鸨(MySQL),大爷(threads),姑娘(innodb)

如何优化innodb_concurrency_tickets,那就得看哪位大爷重要,比如宰相的儿子在这里等,那宰相的儿子又十分持久,最好就用多点时间(增大innodb_concurrency_tickets)

如果宰相的儿子不持久,那就用小时间快点排到他。

3 官方使用建议

在官方文档上,对于innodb_thread_concurrency的使用,也给出了一些建议,如下:

如果一个工作负载中,并发用户线程的数量小于64,建议设置innodb_thread_concurrency=0;

如果工作负载一直较为严重甚至偶尔达到顶峰,建议先设置innodb_thread_concurrency=128,并通过不断的降低这个参数,96, 80, 64等等,直到发现能够提供最佳性能的线程数,例如,假设系统通常有40到50个用户,但定期的数量增加至60,70,甚至200。你会发现,性能在80个并发用户设置时表现稳定,如果高于这个数,性能反而下降。在这种情况下,建议设置innodb_thread_concurrency参数为80,以避免影响性能。

如果你不希望InnoDB使用的虚拟CPU数量比用户线程使用的虚拟CPU更多(比如20个虚拟CPU),建议通过设置innodb_thread_concurrency参数为这个值(也可能更低,这取决于性能体现),如果你的目标是将MySQL与其他应用隔离,你可以考虑绑定mysqld进程到专有的虚拟CPU。但是需要注意的是,这种绑定,在myslqd进程一直不是很忙的情况下,可能会导致非最优的硬件使用率。在这种情况下,你可能会设置mysqld进程绑定的虚拟CPU,允许其他应用程序使用虚拟CPU的一部分或全部。

在某些情况下,最佳的innodb_thread_concurrency参数设置可以比虚拟CPU的数量小。定期检测和分析系统,负载量、用户数或者工作环境的改变可能都需要对innodb_thread_concurrency参数的设置进行调整。

4 笔记

tickets可以理解为MySQL层和Innodb层交互的次数,比如一个select一条数据就是需要Innodb层返回一条数据然后MySQL层进行where条件的过滤然后返回给客户端,抛开where条件过滤的情况,如果我们一条语句需要查询100条数据,那么实际上需要进入Innodb层100次,那么实际上消耗的tickets就是100。当然对于insert select这种操作,需要的tickets是普通select的两倍,因为查询需要进入Innodb层一次,insert需要再次进入Innodb层一次。

这样我们也就理解为什么innodb_concurrency_tickets可以避免(长时间处理线程)长时间堵塞(短时间处理线程)的原因了。假设innodb_concurrency_tickets为5000(默认值),有一个需要查询100W行数据的大select操作和一个需要查询100行数据的小select操作,大select操作先进行,但是当查询了5000行数据后将丢失CPU使用权,小select操作将会进行并且一次性完成。

5 测试和总结

5.1 总结

innodb_thread_concurrency

  • innodb_thread_concurrency是动态参数可以随时修改
  • 64个活跃连接以内直接配0
  • 高压场景需要从高到低测试,找到最优值
  • 高压场景下较低的值可以明显提高写入QPS的占比(高频率的读被限制了)

innodb_thread_sleep_delay(微秒)

  • 定义在开始排队前,等多久加入队列

innodb_adaptive_max_sleep_delay(微秒)

  • 配置innodb_thread_sleep_delay允许的最大值,配了之后innodb会自动调整innodb_thread_sleep_delay的值到一个合适的范围内(自适应算法)

innodb_concurrency_tickets(默认5000)

  • 使用小的值时小事务可以和大事务竞争,缺点是大事务要多次才能跑完
  • 使用大的值时大事务有优势,缺点是可能让小事务一直得不到运行
  • 调整这个值可以参考队列长度,长度从SHOW ENGINE INNODB STATUS来看( ROW OPERATIONS section of SHOW ENGINE INNODB STATUS output),也可以从INFORMATION_SCHEMA.INNODB_TRX的TRX_CONCURRENCY_TICKETS来看。
  • innodb_thread_concurrency限制后活跃连接状态不会变,从innodb_trx能看出来事务是不是在排队,show engine innodb status的row部分也能看出来
  • 对于长短事务的场景应该非常有帮助,适当减少ticket可以让短事务更容易被执行,按下面测试场景来说,一个5读SQL的事务,一个5读3写SQL的事务,两个事务长度基本相同,如果用系统线程调度的话,执行快的事务执行的频率会更高。如果打开排队,每个事务拿着相同的ticket进入innodb,执行次数会更公平。所以可以看到写的次数明显升高了。
  • sysbench的测试场景来说,读影响不是很大

横轴为innodb_thread_concurrency,纵轴为QPS

5.3 90c读写9:1测试

(tickets=5000不变cc变)

sysbench只读模型

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
sysbench oltp_read_only --mysql-host=rm-wz9w4eq0md96sc89x.mysql.rds.aliyuncs.com --mysql-port=3306 --mysql-user=server_234 --mysql-password=server_234 --mysql-db=server_234_db --db-driver=mysql  --tables=64 --table-size=10000000 --rand-type=uniform --report-interval=1 --threads=1024 --time=12000 run

BEGIN
SELECT c FROM sbtest%u WHERE id=?
SELECT c FROM sbtest%u WHERE id BETWEEN ? AND ?
SELECT SUM(k) FROM sbtest%u WHERE id BETWEEN ? AND ?
SELECT c FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY c
SELECT DISTINCT c FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY c
COMMIT

sysbench读写模型

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
sysbench oltp_read_write --mysql-host=rm-wz9w4eq0md96sc89x.mysql.rds.aliyuncs.com --mysql-port=3306 --mysql-user=server_234 --mysql-password=server_234 --mysql-db=server_234_db --db-driver=mysql  --tables=64 --table-size=10000000 --rand-type=uniform --report-interval=1 --threads=1024 --time=12000 run

BEGIN
SELECT c FROM sbtest%u WHERE id=?
SELECT c FROM sbtest%u WHERE id BETWEEN ? AND ?
SELECT SUM(k) FROM sbtest%u WHERE id BETWEEN ? AND ?
SELECT c FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY c
SELECT DISTINCT c FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY c
UPDATE sbtest%u SET k=k+1 WHERE id=?
UPDATE sbtest%u SET c=? WHERE id=?
DELETE FROM sbtest%u WHERE id=?
COMMIT

innodb_thread_sleep_delay=10000

innodb_adaptive_max_sleep_delay=150000

innodb_concurrency_tickets=5000

两客户端每个1024,cc=innodb_thread_concurrency

cc

si

active

cpu|qps

cs

0

3.6

1850

51/38|19.6w

50w

500

3.6

1700

50/40|19.7w

52w

100

3.4

1800

42/48|18.1w

53w

50

2.8

1900

35/53|15.0w

51w

10

0.5

2000

20/6.6|11w

74w

读写qps

Cc

Select

Update

Delete

Insert

0

16.6w

3500

1700

1700

500

16.5w

4000

2000

2000

100

14.8w

6800

3400

3400

50

11.7w

7100

3600

3600

10

8.7w

5400

2700

2700

5.4 无事务测试

(tickets=5000不变cc变)

sysbench只读模型(无事务无范围查询)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
sysbench oltp_read_only --mysql-host=rm-wz9w4eq0md96sc89x.mysql.rds.aliyuncs.com --mysql-port=3306 --mysql-user=server_234 --mysql-password=server_234 --mysql-db=server_234_db --db-driver=mysql  --tables=64 --table-size=10000000 --rand-type=uniform --report-interval=1 --threads=1024 --time=12000 --range_selects=off --skip_trx=on run


SELECT c FROM sbtest%u WHERE id=?

sysbench读写模型(无事务无范围查询)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
sysbench oltp_read_write --mysql-host=rm-wz9w4eq0md96sc89x.mysql.rds.aliyuncs.com --mysql-port=3306 --mysql-user=server_234 --mysql-password=server_234 --mysql-db=server_234_db --db-driver=mysql  --tables=64 --table-size=10000000 --rand-type=uniform --report-interval=1 --threads=1024 --time=12000 --skip_trx=on --range_selects=off run


UPDATE sbtest%u SET k=k+1 WHERE id=?
UPDATE sbtest%u SET c=? WHERE id=?
DELETE FROM sbtest%u WHERE id=?

两客户端每个1024,cc=innodb_thread_concurrency

cc

si

active

cpu|qps

cs

0

3.6

1850

51/38|19.6w

50w

500

3.6

1700

50/40|19.7w

52w

100

3.4

1800

42/48|18.1w

53w

50

2.8

1900

35/53|15.0w

51w

10

0.5

2000

20/6.6|11w

74w

0无事务

2.7

1750

24/67|15.9w

45w

500无事务

2.7

1800

23/68|15w

45w

100无事务

2.5

1900

21/70|14w

47w

50无事务

2.5

1800

20/69|13w

50w

10无事务

1.9

1900

19/60|11w

58w

读写qps

Cc

Select

Update

Delete

Insert

0

16.6w

3500

1700

1700

500

16.5w

4000

2000

2000

100

14.8w

6800

3400

3400

50

11.7w

7100

3600

3600

10

8.7w

5400

2700

2700

0无事务

15.0w

4000

2000

2000

500无事务

15w

4300

2700

2100

100无事务

13w

5500

2700

2700

50无事务

12w

5900

2900

2900

10无事务

10w

7800

3900

3900

innodb_concurrency_tickets=10

innodb_thread_concurrency=10

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> select trx_operation_state,count(*) from information_schema.innodb_trx group by trx_operation_state;
+---------------------------------+----------+
| trx_operation_state             | count(*) |
+---------------------------------+----------+
| NULL                            |       25 |
| sleeping before entering InnoDB |     1932 |
| starting index read             |       10 |
+---------------------------------+----------+
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-04-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
MySQL Innodb 并发涉及参数
MySQL的各个插件式引擎中,都会对事务及线程做一定的处理和优化。在Innodb引擎中,总是尝试保持 innodb内 操作系统的线程数(暂命名为innodb_thread) 应该小于或等于 系统可提供给innodb处理事务的线程数(暂命名为system_innodb_thread)。在大多数情况下,innodb_thread都不会指定一个限制值,而是让它想要多少直接申请多少。
用户1278550
2021/12/21
1.5K0
故障分析 | innodb_thread_concurrency 导致数据库异常的问题分析
作者通过分析源码定位数据库异常,梳理参数 innodb_thread_concurrency 设置的注意事项。
爱可生开源社区
2023/05/22
6750
Mysql重要参数说明
1)mysql double write buffer参数详解 什么是double write buffe?参数innodb_doublewrite=1打开 us_card_online_mysql [(none)] [15:03:01]> show global variables like '%innodb_doublewrite%'; +--------------------+-------+ | Variable_name | Value | +--------------------+
MySQL轻松学
2018/03/09
1.7K0
MySQL 大量sleeping before entering InnoDB 故障诊断
某天下班回家开发给我打电话,反馈MySQL中的一张表被锁了,让我帮他解锁。我一想发生锁了,肯定是某个业务没有及时提交或者有人做了修改没提交。于是我让他把表名以及SQL发给我,我好排除
用户1278550
2019/03/15
1.6K0
mysql innodb_trx参数详解
1、innodb_trx表提供了当前innodb引擎内每个事务的信息(只读事务除外),包括当一个事务启动,事务是否在等待一个锁,以及交易正在执行的语句(如果有的话)。查询语句:
用户14527
2022/03/24
4.1K0
innodb核心配置总结---官方文档阅读笔记
-- 每个表单独文件和单独表空间,而不是放在系统表空间,每个表的文件表空间允许操作系统在表被截断或删除时回收磁盘空间。每表文件表空间还支持动态和压缩行格式以及相关功能
丿丶MySQL灬灬
2021/10/25
1.1K0
MySQL 案例:为什么 kill 不掉线程
在日常的使用过程中,时不时会遇到个别,或者大量的连接堆积在 MySQL 中的现象,这时一般会考虑使用 kill 命令强制杀死这些长时间堆积起来的连接,尽快释放连接数和数据库服务器的 CPU 资源。
王文安@DBA
2021/04/21
4.3K0
MySQL 案例:为什么 kill 不掉线程
MySQL压力测试最佳实践(16/16)
sysbench是一个模块化的、跨平台、多线程基准测试工具,主要用于评估测试各种不同系统参数下的数据库负载情况。项目地址:http://github.com/akopytov/sysbench
十里桃花舞丶
2024/04/12
3870
MySQL压力测试最佳实践(16/16)
MySQL谬误集01:读不加锁
| 导语:生活中的问题有时“难得糊涂”,但技术问题,一是一二是二,忌讳模糊的似是而非的答案,也忌讳一刀切的简单结论。我们常常听到一些关于MySQL的说法,比如“读不加锁”,比如“单表数据要小于1000万”,比如“DDL会锁表”等,比如“单表的索引数量应该小于X个”,如果不加思考和测试就直接全盘接受,就可能犯错误,而DB上的错误又非常“昂贵”,我们应该尽量避免。所以有了想法写10-20篇文章,来思考下这些常见说法是否正确,或者说在什么条件下是正确的。水平所限,也可能文章中会有错误,欢迎大家一起探讨。第1篇文章首先分析下“读不加锁”这种说法是否正确呢?
DBA成江东
2023/07/25
4150
MySQL谬误集01:读不加锁
Mysql长事务总结
在结果中idletime是计算产生的,也是事务的持续时间。但事务的trxquery是NUL,这并不是说事务什么也没执行,一个事务可能包含多个SQL,如果SQL执行完毕就不再显示了。当前事务正在执行,innodb也不知道这个事务后续还有没有sql,啥时候会commit。 因此trx_query不能提供有意义的信息。
mingjie
2022/05/12
9060
Mysql长事务总结
MySQL 性能:使用 MySQL 5.7 实现每秒 50 万查询
使用UNIX socket来运行Point-Selects测试的Sysbench命令如下(在parallel中启动8个进程):
zhangdd
2018/08/01
7330
Mysql优化
1 . 优化不总是对一个单纯的环境进行!还很可能是一个复杂的已投产的系统。优化手段本来就有很大的风险,只不过你没能力意识到和预见到!
iginkgo18
2021/06/21
1.5K0
应用示例荟萃 | performance_schema全方位介绍(上)
经过前面6个篇幅的学习,相信大家对什么是performance_schema,已经初步形成了一个整体认识,但我想很多同行看完之前的文章之后可能还是一脸懵逼,今天就为大家带来performance_schema系列的最后一个篇章(全系共7个篇章),在这一期里,我们将为大家列举数十个performance_schema应用示例。下面,请跟随我们一起开始performance_schema系统的学习之旅吧。
老叶茶馆
2020/11/26
5940
mysql如何进行压力测试?
TPS(Transaction per second)每秒事务量 1052.19
Linux运维技术之路
2022/06/07
1.7K1
mysql如何进行压力测试?
InnoDB隔离模式对MySQL性能的影响
MySQL手册提供了一个关于MySQL支持的事务隔离模式的恰当描述 – 在这里我并不会再重复,而是聚焦到对性能的影响上。
哲洛不闹
2019/06/20
7230
InnoDB隔离模式对MySQL性能的影响
应用示例荟萃 | performance_schema全方位介绍(上)
经过前面6个篇幅的学习,相信大家对什么是performance_schema,已经初步形成了一个整体认识,但我想很多同行看完之前的文章之后可能还是一脸懵逼,今天就为大家带来performance_schema系列的最后一个篇章(全系共7个篇章),在这一期里,我们将为大家列举数十个performance_schema应用示例。下面,请跟随我们一起开始performance_schema系统的学习之旅吧。
沃趣科技
2018/07/02
1.3K0
应用示例荟萃 | performance_schema全方位介绍(上)
MySQL 之压力测试工具
一、MySQL自带的压力测试工具——Mysqlslap mysqlslap是mysql自带的基准测试工具,该工具查询数据,语法简单,灵活容易使用.该工具可以模拟多个客户端同时并发的向服务器发出查询更新,给出了性能测试数据而且提供了多种引擎的性能比较。mysqlslap为mysql性能优化前后提供了直观的验证依据,系统运维和DBA人员应该掌握一些常见的压力测试工具,才能准确的掌握线上数据库支撑的用户流量上限及其抗压性等问题。 1、更改其默认的最大连接数 在对MySQL进行压力测试之前,需要更改其默认的最大连接数,如下:
小手冰凉
2020/05/27
4.2K0
[MYSQL] show engine innodb status中的死锁 分析
很久以前(也才2年)写过一个解析innodb_status的脚本. 看起来像那么回事, 其实就是做了个翻译和总结.
大大刺猬
2024/08/26
8280
[MYSQL] show engine innodb status中的死锁 分析
Xtrabackup在线搭建备库与并行复制延迟
为了兼容 MySQL 5.6 基于库的并行复制,5.7 引入了新的变量 slave-parallel-type,其可以配置的值有:
mingjie
2022/05/12
4730
Xtrabackup在线搭建备库与并行复制延迟
Mysql一分钟定位 Next-Key Lock,你需要几分钟
查看线程模型 show variables like 'thread_handling'
王清培
2020/01/27
4140
相关推荐
MySQL Innodb 并发涉及参数
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验