【PostgreSQL在线创建索引(CIC)功能的锁分析以及使用注意】

前一篇文章提到了普通创建索引会阻塞DML操作

PostgreSQL创建索引的锁分析和使用注意

而PostgreSQL里可以使用create index concurrently 在线创建索引(CIC)功能,降低创建索引在表上申请的锁的级别,ShareUpdateExclusiveLock级别的锁和RowExclusiveLock不冲突,不会阻塞表上的DML操作。

1.1 在线创建索引(CIC)的原理

并发创建索引需要分多个步骤完成,首先在一个事务中将相关索引信息记录到系统表中,但是将索引信息标记为非法状态,然后需要进行两次扫描,并且在最后需要等待第二次扫描之前产生的所有具有快照信息的事务结束,最后修改索引的状态信息为可用。

1.插入元数据
|在系统表中插入索引的元数据,包括pg_class、pg_index,索引信息标记为非法状态(INVALID),然后开启两个事务,进行两次扫描

2.第一次扫描

|开启事务1,拿到当前snapshot1
	|扫描test_tab1表前,等待所有修改过test1表(写入、删除、更新)的事务结束
		|扫描test_tab1表,并建立中间状态的索引(INVALID)
			|结束事务1
			
2.第二次扫描

|开启事务2,拿到当前snapshot2
	|再次扫描test_tab1表前,等待所有修改过test_tab1表(写入、删除、更新)的事务结束
		|在snapshot2之后启动的事务对test_tab1表执行的DML,会修改这个idx_1的索引
			|再次扫描test_tab1表,更新索引。(从tuple中可以拿到版本号,在snapshot1到snapshot2之间变更的记录,将其合并到索引)
				|上一步更新索引结束后,等待事务2之前开启的持有snapshot的事务结束
					|结束索引创建,索引可见

可以看到CREATE INDEX CONCURRENTLY在线创建索引(CIC)是需要借助snapshot去完成操作的,所以其实如果有长事务占用了快照,让它获取不到锁,那么创建的时间就会很长。

1.2 在线创建索引(CIC)操作在表上获取的锁(ShareUpdateExclusiveLock)

如之前测试的现象,在一张表上创建普通B-tree索引的时候,会阻塞这张表上进行的DML操作。PostgreSQL支持在线创建索引(CREATE INDEX CONCURRENTLY),不堵塞其他会话对被创建索引表的DML(INSERT,UPDATE,DELETE)操作。

postgres=# begin;
BEGIN
postgres=*# create index concurrently idx_111 on t1(id);
ERROR:  CREATE INDEX CONCURRENTLY cannot run inside a transaction block
postgres=!# 

而create index concurrently操作不能在一个显式开启的事务里执行,并且我自己的环境也比较有限,就不造数据模拟了,而是使用gdb在对应函数打上Breakpoint,进行分析。

(gdb) b LockAcquireExtended
Breakpoint 1 at 0xaaaab094d094: file lock.c, line 765.
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000aaaab094d094 in LockAcquireExtended at lock.c:765

image20240104175113090.png

(gdb) c
Continuing.

Breakpoint 1, LockAcquireExtended (locktag=locktag@entry=0xffffc42c3f08, lockmode=lockmode@entry=1, sessionLock=sessionLock@entry=false, dontWait=dontWait@entry=false, reportMemoryError=reportMemoryError@entry=true, locallockp=locallockp@entry=0xffffc42c3f00) at lock.c:765
765     {
(gdb) bt
#0  LockAcquireExtended (locktag=locktag@entry=0xffffc42c3f08, lockmode=lockmode@entry=1, sessionLock=sessionLock@entry=false,
    dontWait=dontWait@entry=false, reportMemoryError=reportMemoryError@entry=true, locallockp=locallockp@entry=0xffffc42c3f00) at lock.c:765
#1  0x0000aaaab0949ffc in LockRelationOid (relid=3466, lockmode=1) at lmgr.c:117
#2  0x0000aaaab058c1a8 in relation_open (relationId=relationId@entry=3466, lockmode=lockmode@entry=1) at relation.c:56
#3  0x0000aaaab0aa3fb4 in BuildEventTriggerCache () at evtcache.c:130
#4  EventCacheLookup (event=<optimized out>, event@entry=EVT_SQLDrop) at evtcache.c:69
#5  0x0000aaaab07018c0 in trackDroppedObjectsNeeded () at event_trigger.c:1147
#6  EventTriggerBeginCompleteQuery () at event_trigger.c:1089
#7  0x0000aaaab096cd48 in ProcessUtilitySlow (pstate=pstate@entry=0xaaaac6004f58, pstmt=pstmt@entry=0xaaaac60827d0,
    queryString=queryString@entry=0xaaaac6081b98 "create index concurrently idx_1 on tab_test_1(id);", context=context@entry=PROCESS_UTILITY_TOPLEVEL,
    params=params@entry=0x0, queryEnv=queryEnv@entry=0x0, qc=qc@entry=0xffffc42c4ab8, dest=<optimized out>) at utility.c:1118
#8  0x0000aaaab096c0d4 in standard_ProcessUtility (pstmt=0xaaaac60827d0, queryString=0xaaaac6081b98 "create index concurrently idx_1 on tab_test_1(id);",
    readOnlyTree=<optimized out>, context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0xaaaac6083000, qc=0xffffc42c4ab8) at utility.c:1078
#9  0x0000ffff90026270 in pgss_ProcessUtility (pstmt=0xaaaac60827d0, queryString=0xaaaac6081b98 "create index concurrently idx_1 on tab_test_1(id);",
    readOnlyTree=false, context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0xaaaac6083000, qc=0xffffc42c4ab8) at pg_stat_statements.c:1145
#10 0x0000aaaab096a6cc in PortalRunUtility (portal=portal@entry=0xaaaac6104e88, pstmt=pstmt@entry=0xaaaac60827d0, isTopLevel=isTopLevel@entry=true,
    setHoldSnapshot=setHoldSnapshot@entry=false, dest=dest@entry=0xaaaac6083000, qc=qc@entry=0xffffc42c4ab8) at pquery.c:1158
#11 0x0000aaaab096a874 in PortalRunMulti (portal=portal@entry=0xaaaac6104e88, isTopLevel=isTopLevel@entry=true,
    setHoldSnapshot=setHoldSnapshot@entry=false, dest=dest@entry=0xaaaac6083000, altdest=altdest@entry=0xaaaac6083000, qc=qc@entry=0xffffc42c4ab8)
    at pquery.c:1315
#12 0x0000aaaab096ae00 in PortalRun (portal=portal@entry=0xaaaac6104e88, count=count@entry=9223372036854775807, isTopLevel=isTopLevel@entry=true,
    run_once=run_once@entry=true, dest=dest@entry=0xaaaac6083000, altdest=altdest@entry=0xaaaac6083000, qc=qc@entry=0xffffc42c4ab8) at pquery.c:791
#13 0x0000aaaab0966768 in exec_simple_query (query_string=query_string@entry=0xaaaac6081b98 "create index concurrently idx_1 on tab_test_1(id);")
    at postgres.c:1274
#14 0x0000aaaab0967648 in PostgresMain (dbname=<optimized out>, username=<optimized out>) at postgres.c:4637
#15 0x0000aaaab08c0514 in BackendRun (port=0xaaaac60b6c40, port=0xaaaac60b6c40) at postmaster.c:4464
#16 BackendStartup (port=0xaaaac60b6c40) at postmaster.c:4192
#17 ServerLoop () at postmaster.c:1782
#18 0x0000aaaab08c165c in PostmasterMain (argc=argc@entry=1, argv=argv@entry=0xaaaac5fe9d40) at postmaster.c:1466
#19 0x0000aaaab0578464 in main (argc=1, argv=0xaaaac5fe9d40) at main.c:198

image20240104175201418.png


上面停掉的第一个Breakpoint,其可以看一下调用到LockAcquireExtended的堆栈,relation_open (relationId=relationId@entry=3466, lockmode=lockmode@entry=1) at relation.c:56 这里oid对应是3466的并不是索引所在的表,而是系统表,因为创建索引过程也会访问系统表,开始连续几个停的断点的位置,打印的lockmode都是1,获取的都是AccessShareLock,也就是说这几个系统表都是进行了select的操作。这里我们就带着目的去看,继续让他往下跑,一直等到这个lockmode为4的时候,relation_open (relationId=relationId@entry=16725,因为我们创建索引的这张表tab_test_1,它对应的oid是16725。lockmode为4对应的就是ShareUpdateExclusiveLock。

postgres=# select oid,relname from pg_class where relname='tab_test_1';
  oid  |  relname
-------+------------
 16725 | tab_test_1
(1 row)
765     {
(gdb) c
Continuing.

Breakpoint 1, LockAcquireExtended (locktag=locktag@entry=0xffffc42c3d78, lockmode=lockmode@entry=1, sessionLock=sessionLock@entry=false, dontWait=dontWait@entry=false, reportMemoryError=reportMemoryError@entry=true, locallockp=locallockp@entry=0xffffc42c3d70) at lock.c:765
765     {
(gdb) c
Continuing.

Breakpoint 1, LockAcquireExtended (locktag=locktag@entry=0xffffc42c3fd8, lockmode=lockmode@entry=4, sessionLock=sessionLock@entry=false, dontWait=dontWait@entry=false, reportMemoryError=reportMemoryError@entry=true, locallockp=locallockp@entry=0xffffc42c3fd0) at lock.c:765
765     {
(gdb) bt
#0  LockAcquireExtended (locktag=locktag@entry=0xffffc42c3fd8, lockmode=lockmode@entry=4, sessionLock=sessionLock@entry=false,
    dontWait=dontWait@entry=false, reportMemoryError=reportMemoryError@entry=true, locallockp=locallockp@entry=0xffffc42c3fd0) at lock.c:765
#1  0x0000aaaab0949ffc in LockRelationOid (relid=relid@entry=16725, lockmode=lockmode@entry=4) at lmgr.c:117
#2  0x0000aaaab0672290 in RangeVarGetRelidExtended (relation=0xaaaac60825b8, lockmode=lockmode@entry=4, flags=flags@entry=0,
    callback=0xaaaab074e5d0 <RangeVarCallbackOwnsRelation>, callback_arg=callback_arg@entry=0x0) at namespace.c:390
#3  0x0000aaaab096d1f8 in ProcessUtilitySlow (pstate=pstate@entry=0xaaaac61ba098, pstmt=pstmt@entry=0xaaaac60827d0,
    queryString=queryString@entry=0xaaaac6081b98 "create index concurrently idx_1 on tab_test_1(id);", context=context@entry=PROCESS_UTILITY_TOPLEVEL,
    params=params@entry=0x0, queryEnv=queryEnv@entry=0x0, qc=qc@entry=0xffffc42c4ab8, dest=<optimized out>) at utility.c:1486
#4  0x0000aaaab096c0d4 in standard_ProcessUtility (pstmt=0xaaaac60827d0, queryString=0xaaaac6081b98 "create index concurrently idx_1 on tab_test_1(id);",
    readOnlyTree=<optimized out>, context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0xaaaac6083000, qc=0xffffc42c4ab8) at utility.c:1078
#5  0x0000ffff90026270 in pgss_ProcessUtility (pstmt=0xaaaac60827d0, queryString=0xaaaac6081b98 "create index concurrently idx_1 on tab_test_1(id);",
    readOnlyTree=false, context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0xaaaac6083000, qc=0xffffc42c4ab8) at pg_stat_statements.c:1145
#6  0x0000aaaab096a6cc in PortalRunUtility (portal=portal@entry=0xaaaac6104e88, pstmt=pstmt@entry=0xaaaac60827d0, isTopLevel=isTopLevel@entry=true,
    setHoldSnapshot=setHoldSnapshot@entry=false, dest=dest@entry=0xaaaac6083000, qc=qc@entry=0xffffc42c4ab8) at pquery.c:1158
#7  0x0000aaaab096a874 in PortalRunMulti (portal=portal@entry=0xaaaac6104e88, isTopLevel=isTopLevel@entry=true,
    setHoldSnapshot=setHoldSnapshot@entry=false, dest=dest@entry=0xaaaac6083000, altdest=altdest@entry=0xaaaac6083000, qc=qc@entry=0xffffc42c4ab8)
    at pquery.c:1315
#8  0x0000aaaab096ae00 in PortalRun (portal=portal@entry=0xaaaac6104e88, count=count@entry=9223372036854775807, isTopLevel=isTopLevel@entry=true,
    run_once=run_once@entry=true, dest=dest@entry=0xaaaac6083000, altdest=altdest@entry=0xaaaac6083000, qc=qc@entry=0xffffc42c4ab8) at pquery.c:791
#9  0x0000aaaab0966768 in exec_simple_query (query_string=query_string@entry=0xaaaac6081b98 "create index concurrently idx_1 on tab_test_1(id);")
    at postgres.c:1274
#10 0x0000aaaab0967648 in PostgresMain (dbname=<optimized out>, username=<optimized out>) at postgres.c:4637
#11 0x0000aaaab08c0514 in BackendRun (port=0xaaaac60b73e0, port=0xaaaac60b73e0) at postmaster.c:4464
#12 BackendStartup (port=0xaaaac60b73e0) at postmaster.c:4192
#13 ServerLoop () at postmaster.c:1782
#14 0x0000aaaab08c165c in PostmasterMain (argc=argc@entry=1, argv=argv@entry=0xaaaac5fe9d40) at postmaster.c:1466
#15 0x0000aaaab0578464 in main (argc=1, argv=0xaaaac5fe9d40) at main.c:198

image202401041820106884363613.png

s单步执行,然后p打印出变量的值

image202401041827194944364041.png

上面 *locktag里locktag_type是0,结合LockTagType的定义,第一个定义的enum值默认为0,后续的值在前一个定义值的基础上加1,可以知道是申请的LOCKTAG_RELATION,表锁。

/*
 * The LOCKTAG struct is defined with malice aforethought to fit into 16
 * bytes with no padding.  Note that this would need adjustment if we were
 * to widen Oid, BlockNumber, or TransactionId to more than 32 bits.
 *
 * We include lockmethodid in the locktag so that a single hash table in
 * shared memory can store locks of different lockmethods.
 */
typedef struct LOCKTAG
{
	uint32		locktag_field1; /* a 32-bit ID field */
	uint32		locktag_field2; /* a 32-bit ID field */
	uint32		locktag_field3; /* a 32-bit ID field */
	uint16		locktag_field4; /* a 16-bit ID field */
	uint8		locktag_type;	/* see enum LockTagType */
	uint8		locktag_lockmethodid;	/* lockmethod indicator */
} LOCKTAG;
/*
 * LOCKTAG is the key information needed to look up a LOCK item in the
 * lock hashtable.  A LOCKTAG value uniquely identifies a lockable object.
 *
 * The LockTagType enum defines the different kinds of objects we can lock.
 * We can handle up to 256 different LockTagTypes.
 */
typedef enum LockTagType
{
	LOCKTAG_RELATION,			/* whole relation */
	LOCKTAG_RELATION_EXTEND,	/* the right to extend a relation */
	LOCKTAG_DATABASE_FROZEN_IDS,	/* pg_database.datfrozenxid */
	LOCKTAG_PAGE,				/* one page of a relation */
	LOCKTAG_TUPLE,				/* one physical tuple */
	LOCKTAG_TRANSACTION,		/* transaction (for waiting for xact done) */
	LOCKTAG_VIRTUALTRANSACTION, /* virtual transaction (ditto) */
	LOCKTAG_SPECULATIVE_TOKEN,	/* speculative insertion Xid and token */
	LOCKTAG_OBJECT,				/* non-relation database object */
	LOCKTAG_USERLOCK,			/* reserved for old contrib/userlock code */
	LOCKTAG_ADVISORY			/* advisory user locks */
} LockTagType;

1.3 在线创建索引(CIC)被阻塞的案例(等待vxid)

//session 1:pid 557584
postgres=# begin;
BEGIN
postgres=*# select id from tab_test_2 for update;
 id
----
  1
(1 row)

//session 2:pid 557784
postgres=# select id from tab_test_2 for update;
被阻塞

//session 3:pid 558431
postgres=# create index concurrently idx_1 on tab_test_1(id);
被阻塞

//session 4:

(1)可以使用pg_blocking_pids查看被谁阻塞了
postgres=# select pg_blocking_pids('558431');
 pg_blocking_pids
------------------
 {557784}
(1 row)

postgres=# select pg_blocking_pids('557784');
 pg_blocking_pids
------------------
 {557584}
(1 row)

(2)也可以像下边查询锁的情况

postgres=# select* from pg_locks
                            where pid in('557584','557784','558431');
   locktype    | database | relation | page | tuple | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction |  pid   |           mod
e           | granted | fastpath |           waitstart
---------------+----------+----------+------+-------+------------+---------------+---------+-------+----------+--------------------+--------+--------------
------------+---------+----------+-------------------------------
 virtualxid    |          |          |      |       | 5/309      |               |         |       |          | 5/309              | 558431 | ExclusiveLock
            | t       | t        |
 relation      |    13008 |    24929 |      |       |            |               |         |       |          | 4/46               | 557784 | RowShareLock
            | t       | t        |
 relation      |    13008 |    24929 |      |       |            |               |         |       |          | 3/202              | 557584 | RowShareLock
            | t       | t        |
 virtualxid    |          |          |      |       | 3/202      |               |         |       |          | 3/202              | 557584 | ExclusiveLock
            | t       | t        |
 transactionid |          |          |      |       |            |          1719 |         |       |          | 3/202              | 557584 | ExclusiveLock
            | t       | f        |
 virtualxid    |          |          |      |       | 4/46       |               |         |       |          | 5/309              | 558431 | ShareLock
            | f       | f        | 2024-01-05 13:37:45.5214+08
 relation      |    13008 |    24925 |      |       |            |               |         |       |          | 5/309              | 558431 | ShareUpdateEx
clusiveLock | t       | f        |
 tuple         |    13008 |    24929 |    0 |     1 |            |               |         |       |          | 4/46               | 557784 | AccessExclusi
veLock      | t       | f        |
 transactionid |          |          |      |       |            |          1719 |         |       |          | 4/46               | 557784 | ShareLock
            | f       | f        | 2024-01-05 13:37:42.613288+08
 virtualxid    |          |          |      |       | 4/46       |               |         |       |          | 4/46               | 557784 | ExclusiveLock
            | t       | f        |
(10 rows)

image2024010514013910044345004434501.png

"virtualxid"和"virtualtransaction"从字面上看都是虚拟事务ID的意思。它们的区别是:位于pg_locks视图的不同部分,"virtualxid"位于描述锁对象的部分, "virtualtransaction"位于描述持有锁或等待锁的部分。因此,"virtualxid"表示这个锁对象是一个虚拟事务,而"virtualtransaction"表示持有锁或等待锁的虚拟事务ID。

通过上图可以看出, 5/309是建索引本身的vxid,建索引需要等老事务结束,所以用vxid等另外一个会话结束,可以看到最后一行在请求别人的vxid 4/46。而这个vxid 4/46刚好是pid为557584的会话持有的,所以这个阻塞不是等待获取表上的锁,是在等待vxid的锁。

使用pstack 看一下现在被阻塞的这个会话的堆栈

root@ubuntu-linux-22-04-desktop:~# pstack 558431
#0  0x0000ffff8faf5ea8 in epoll_pwait () from /lib/aarch64-linux-gnu/libc.so.6
#1  0x0000aaaae03e778c in WaitEventSetWait ()
#2  0x0000aaaae03e7b30 in WaitLatch ()
#3  0x0000aaaae040b428 in ProcSleep ()
#4  0x0000aaaae03fc064 in WaitOnLock ()
#5  0x0000aaaae03fd410 in LockAcquireExtended ()
#6  0x0000aaaae0400f54 in VirtualXactLock ()
#7  0x0000aaaae01c93b4 in WaitForOlderSnapshots ()
#8  0x0000aaaae01cd930 in DefineIndex ()
#9  0x0000aaaae041d270 in ProcessUtilitySlow.constprop.0 ()
#10 0x0000aaaae041c0d4 in standard_ProcessUtility ()
#11 0x0000ffff8f426270 in pgss_ProcessUtility () from /home/postgres/soft-16/lib/pg_stat_statements.so
#12 0x0000aaaae041a6cc in PortalRunUtility ()
#13 0x0000aaaae041a874 in PortalRunMulti ()
#14 0x0000aaaae041ae00 in PortalRun ()
#15 0x0000aaaae0416768 in exec_simple_query ()
#16 0x0000aaaae0417648 in PostgresMain ()
#17 0x0000aaaae0370514 in ServerLoop ()
#18 0x0000aaaae037165c in PostmasterMain ()
#19 0x0000aaaae0028464 in main ()

DefineIndex()主要是处理索引创建的逻辑,而常规锁的申请主要在接口 LockAcquire() 和 LockAcquireExtended()中实现。可以看到堆栈的最后处于等待的状态。

image202401051427100754436032.png

可以看一下其中的变量,这个relationId=24925对应的对象就是我们要创建的索引所在的表,而对应的locktag_type = 6,结合LockTagType的定义,可以知道这个6代表的是LOCKTAG_VIRTUALTRANSACTION,对virtual transaction申请锁,锁是5级,表示ShareLock,看到是不是有疑问了,之前说CIC的锁相对于普通的建立索引降低了一个级别,变成了4级锁,但是这里是5级锁,其实是不一样的,这块获取的锁的locktag_type并不是针对relation的,而是针对virtual transaction的,源码注释里关于常规锁模式解析部分的也是针对于relation的。

image202401051433428504436424.png

postgres=# select '24925'::regclass;

  regclass
------------

 tab_test_1
(1 row)

所以真正CIC过程表上的锁,应该找到一个relation oid=24925,LockAcquireExtended()函数执行过程locktag->locktag_type为0时,再查看lockmode的值。这里再次重新用gdb打上一个breakpoint,抓到了表上申请的锁,果然是4级锁,即ShareUpdateExclusiveLock。

image202401051509166864438558.png

1.4 在线创建索引(CIC)操作的可能遇到的问题

PostgreSQL支持在线创建索引(CREATE INDEX CONCURRENTLY),不堵塞其他会话对被创建索引表的DML(INSERT,UPDATE,DELETE)操作,所以有时候为了不阻塞业务,采用CIC,而不是使用普通创建索引的方式。

问题:

1.执行速度慢

​ 从在线创建索引(CIC)的实现机制上可以看出,它需要两次扫描表。所以不考虑锁阻塞的情况下它的执行时间可能会比正常创建索引慢很多。

2.执行失败后可能存在INVALID索引

​ 因为第一次扫描并建立中间状态的索引(INVALID)后,索引实际上就对后面的DML起作用了,所以如果是在第二SCAN阶段,索引创建失败了,这个索引会一直影响DML(性能、约束)。

3.冲突,不允许同时执行

create index concurrently 在线创建索引(CIC)功能无法并发执行,因为这个操作在表上上的是ShareUpdateExclusiveLock锁,四级锁,自斥。

解决方法:

第一个问题:

​ 扫描两次表的这个问题,是其本身机制的问题,只能尽量选取在业务不忙的时候,除此之外,尽量避免阻塞情况:

  1. 尽量避免创建索引过程中,两次SCAN之前对被创建索引表实施长事务,并且长事务中包含修改被创建索引的表。
  2. 在第二次SCAN前,尽量避免开启长事务。

第二个问题:

​ 因为CIC的实现机制问题,如果索引创建失败后,可能会留下一个失效索引。失效索引不能被使用,而且在进行DML的时候,也会一并进行更改,浪费主机资源。可以查看pg_index视图的indisvalid字段。如果为真,此索引当前可以用于查询,为假表示此索引可能不完整,需要进行处理,根据需求重建或者删除掉。

第三个问题:

​ 注意不要多个session同时对一张表做create index concurrently操作,以防冲突。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/303360.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解决Qt Creator中文乱码的问题

方法1 使用QStringLiteral()包裹中文字符串 QString str1"中文测试&#xff01;"; QString str2QStringLiteral("中文测试&#xff01;");方法2 #if _MSC_VER > 1600//MSVC2015>1899,MSVC_VER14.0 #pragma execution_character_set("utf-8&qu…

第二百五十四回

文章目录 1. 概念介绍2. 思路与方法2.1 实现思路2.2 实现方法 3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"如何给图片添加阴影"相关的内容&#xff0c;本章回中将介绍自定义Radio组件.闲话休提&#xff0c;让我们一起Talk Flutter吧…

7个Pandas绘图函数助力数据可视化

大家好&#xff0c;在使用Pandas分析数据时&#xff0c;会使用Pandas函数来过滤和转换列&#xff0c;连接多个数据帧中的数据等操作。但是&#xff0c;生成图表将数据在数据帧中可视化&#xff0c;通常比仅仅查看数字更有帮助。 Pandas具有几个绘图函数&#xff0c;可以使用它…

Java面向对象综合练习(拼图小游戏),用java图形化界面实现拼图小游戏

1. 设计游戏的目的 锻炼逻辑思维能力利用Java的图形化界面&#xff0c;写一个项目&#xff0c;知道前面学习的知识点在实际开发中的应用场景 2. 游戏的最终效果呈现 Hello&#xff0c;各位同学大家好。今天&#xff0c;我们要写一个非常有意思的小游戏 —《拼图小游戏》 我们…

【机器学习】循环神经网络(三)

四、序列预测问题 循环神经网络实现的序列到序列的映射&#xff08;Recurrent Neural Network based Sequence-to-Sequence Mapping&#xff09;是一种使用循环神经网络来将一个序列数据映射到另一个序列数据的方法&#xff0c;它可以用于机器翻译、文本摘要、对话生成等任务。…

多国管理中心多语言区块链源码一元夺宝程序仿趣步奕跑/原生计步器/原生人脸识别

前后台分开的&#xff0c;后台是TP3.2的框架了&#xff0c;应该是比较老的程序了。 目前把整体UI 改版黄色系风格&#xff0c;集成了一元夺宝程序&#xff0c;用户数据同步趣步&#xff0c;效果看起来很棒&#xff0c;另外加入股票走势图&#xff08;K线图&#xff09;&#xf…

使用即时设计绘制原型设计方便吗?和Axure RP相比怎么样?

对于原型设计&#xff0c;APP 和 Web 都是一样的&#xff0c;因为产品原型是用来确定需求的工具。我们使用这种工具的目的是为了快速迭代&#xff0c;从而深入挖掘和筛选产品的需求。 绘制原型&#xff0c;最重要的原则是&#xff1a;快速、清晰&#xff01; Axure 工具的优缺…

“单项突出”的赢双科技IPO加速,比亚迪是最强助力?

近日&#xff0c;新能源汽车核心部件供应商赢双科技首次递表科创板&#xff0c;其凭借旋转变压器产品就坐稳了新能源车企主要供应商的地位&#xff0c;从核心业务及业绩情况来看&#xff0c;赢双科技不愧为“单项冠军”。 据悉&#xff0c;赢双科技本次IPO拟募资8.47亿元&…

css中有哪些方式可以隐藏页面元素?区别?

面试官&#xff1a;css中&#xff0c;有哪些方式可以隐藏页面元素&#xff1f;区别? 一、前言 在平常的样式排版中&#xff0c;我们经常遇到将某个模块隐藏的场景 通过css隐藏元素的方法有很多种&#xff0c;它们看起来实现的效果是一致的 但实际上每一种方法都有一丝轻微的…

短视频矩阵系统+无人直播源码+视频批量分发----开发实践

核心技术 1. AI自动直播&#xff1a; 智能系统通过丰富可定制的文案库&#xff0c; 拥有有料有趣的灵魂。不仅能自动语音讲解内容&#xff0c;还可以在直播中和用户灵活互动。直播中可将团购商品同话术自动上下架。 2. AI剪辑 可一键智能批量成片&#xff0c;也可跟着模板剪…

XDOJ78.机器人

标题 机器人 类别 综合 时间限制 1S 内存限制 256Kb 问题描述 机器人按照给定的指令在网格中移动&#xff0c;指令有以下四种&#xff1a; N 向北&#xff08;上&#xff09;移动 S 向南&#xff08;下&#xff09;移动 E 向东&#xff08;右&#xff09;移动 W 向西&…

国标GB28181视频监控EasyCVR平台:视频集中录制存储/云端录像功能及操作介绍

安防视频监控系统EasyCVR视频综合管理平台&#xff0c;采用了开放式的网络结构&#xff0c;可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、云存储等丰富的视频能力&#xff0c;同时还具备权限管理、设…

linux centos 账户管理命令

在CentOS或其他基于Linux的系统上&#xff0c;账户管理涉及到用户的创建、修改、删除以及密码的管理等任务。 linux Centos账户管理命令 1 创建用户&#xff1a; useradd username 这将创建一个新用户&#xff0c;但默认不会创建家目录。如果想要创建家目录&#xff0c;可以…

19、Kubernetes核心技术 - 资源限制

目录 一、概述 二、Kubernetes 中的资源单位 2.1、CPU资源单位 2.2、内存资源单位 三、Pod资源限制 四、namespace资源限制 4.1、为命名空间配置内存和 CPU 配额 4.2、为命名空间配置默认的内存请求和限制 4.3、为命名空间配置默认的CPU请求和限制 五、超过容器限制的…

FreeRTOS概述

什么是FreeRTOSFreeRTOS官网地址 FreeRTOS 是市场领先的面向微控制器和小型微处理器的实时操作系统 (RTOS)&#xff0c;与世界领先的芯片公司合作开发&#xff0c;现在每 170 秒下载一次。MIT 通过 FreeRTOS 开源许可免费分发&#xff0c;包括一个内核和一组不断丰富的 IoT 库&…

muduo网络库剖析——日志Log类

muduo网络库剖析——日志Log类 前情从muduo到my_muduo 概要日志日志级别 框架与细节成员函数 源码 前情 从muduo到my_muduo 作为一个宏大的、功能健全的muduo库&#xff0c;考虑的肯定是众多情况是否可以高效满足&#xff1b;而作为学习者&#xff0c;我们需要抽取其中的精华…

【Leetcode】240. 搜索二维矩阵 II

一、题目 1、题目描述 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性: 每行的元素从左到右升序排列。每列的元素从上到下升序排列。示例1: 输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21…

新火种AI|小冰摊牌了!大模型已获国内备案,克隆人发布箭在弦上...

作者&#xff1a;小岩 编辑&#xff1a;彩云 2024年国内AI圈的第一个重磅消息已然来袭。 1月4日&#xff0c;小冰公司宣布&#xff0c;已于去年12月成功获得“小冰大模型”的国内备案。结合此前公司在日本研发的Rinna大模型&#xff0c;小冰方面称&#xff0c;公司已实现不同…

视频会员付费系统源码 影视视频模版源码 模板PC+WAP苹果CMS影视模板源码

快猫视频会员付费视频系统/x站视频模板/苹果CMS影视模板/可打包成双端APP 适用程序&#xff1a;苹果cmsv10 兼容性和面向场景&#xff1a; 1、Windows 平台&#xff1a; IIS/Apache PHP&#xff08;5.6&#xff09; MySQL&#xff08;5.5&#xff09; 2、Linux/Unix 平台…

深度学习|4.7 参数和超参数

4.7 参数和超参数 超参数是指需要用户提前设置好的参数&#xff0c;这些超参数最终会影响到参数的数值&#xff08;相当于参数是动态调整得到的&#xff09; 学习率的选取 最优学习率应该能使得代价函数趋于一个较低的常数。
最新文章