PostgreSql 锁

news2025/1/17 0:17:55

一、概述

  在 PostgreSQL 事务中提到,多个用户访问相同数据时可能出现脏读,不可重复度,幻读,更新丢失的问题,为解决这些问题,定义了不同的隔离级别,而隔离级别的具体实现,依靠的就是数据库锁冲突的机制,在数据库中,不同事务在同一时刻不能对同一对象持有相互冲突的锁,PostgreSQL 提供了多种锁模式用于控制对表中数据的并发访问,大多数情况下数据库会在事务运行的过程中自动的给相关对象加锁解锁,以保证事物的正常运行及数据的一致性。

二、分类

2.1 表级锁

  两个事务在同一时刻不能在同一个表上持有相互冲突的锁,非冲突锁可以由许多事务同时持有。特别注意,一个事务决不会和自身冲突,例如,它可以在同一个表上获得 ACCESS EXCLUSIVE 锁然后接着获取 ACCESS SHARE 锁。表级锁冲突矩阵如下,空白表示两种锁可相互兼容,X 表示两种锁相互冲突。
在这里插入图片描述

  • ACCESS SHARE:只与 ACCESS EXCLUSIVE 锁模式冲突。SELECT 命令在被引用的表上获得一个这种模式的锁。通常,任何只读取表而不修改它的查询都将获得这种模式的锁。
  • ROW SHARE:与 EXCLUSIVE 和 ACCESS EXCLUSIVE 锁模式冲突。SELECT FOR UPDATE 和SELECT FOR SHARE 命令在目标表上取得一个这种模式的锁。
  • ROW EXCLUSIVE:与 SHARE、SHARE ROW EXCLUSIVE、EXCLUSIVE 和 ACCESS EXCLUSIVE 锁模式冲突。命令 UPDATE、DELETE 和 INSERT 在目标表上取得这种锁模式。通常,这种锁模式将被任何修改表中数据的命令取得。
  • SHARE UPDATE EXCLUSIVE:与 SHARE UPDATE EXCLUSIVE、SHARE、SHARE ROW EXCLUSIVE、EXCLUSIVE 和 ACCESS EXCLUSIVE 锁模式冲突。这种模式保护一个表不受并发模式改变和 VACUUM 运行的影响。VACUUM(不带FULL)、ANALYZE、 CREATE INDEX CONCURRENTLY、REINDEX CONCURRENTLY、 CREATE STATISTICS 以及某些 ALTER INDEX 和 ALTER TABLE 的变体获得这种模式的锁。
  • SHARE:与 ROW EXCLUSIVE、SHARE UPDATE EXCLUSIVE、SHARE ROW EXCLUSIVE、EXCLUSIVE 和 ACCESS EXCLUSIVE 锁模式冲突。这种模式保护一个表不受并发数据改变的影响。CREATE INDEX(不带 CONCURRENTLY)将获得这种模式的锁。
  • SHARE ROW EXCLUSIVE:与 ROW EXCLUSIVE、SHARE UPDATE EXCLUSIVE、SHARE、SHARE ROW EXCLUSIVE、EXCLUSIVE 和 ACCESS EXCLUSIVE 锁模式冲突。这种模式保护一个表不受并发数据修改所影响,并且是自排他的,这样在一个时刻只能有一个会话持有它。CREATE TRIGGER 和某些形式的 ALTER TABLE 将获得这种模式的锁。
  • EXCLUSIVE:与 ROW SHARE、ROW EXCLUSIVE、SHARE UPDATE EXCLUSIVE、SHARE、SHARE ROW EXCLUSIVE、EXCLUSIVE 和 ACCESS EXCLUSIVE 锁模式冲突。这种模式只允许并发的 ACCESS SHARE 锁,即只有来自于表的读操作可以与一个持有该锁模式的事务并行处理。REFRESH MATERIALIZED VIEW CONCURRENTLY 将获得这种模式的锁。
  • ACCESS EXCLUSIVE:与所有模式的锁冲突(ACCESS SHARE、ROW SHARE、ROW EXCLUSIVE、SHARE UPDATE EXCLUSIVE、SHARE、SHARE ROW EXCLUSIVE、EXCLUSIVE 和 ACCESS EXCLUSIVE)。这种模式保证持有者是访问该表的唯一事务。ALTER TABLE、DROP TABLE、TRUNCATE、REINDEX、CLUSTER、VACUUM FULL和REFRESH MATERIALIZED VIEW(不带CONCURRENTLY)命令将获得这种模式的锁。很多形式的 ALTER INDEX 和 ALTER TABLE 也在这个层面上获得锁。这也是未显式指定模式的 LOCK TABLE 命令的默认锁模式。

示例
窗口 a 开启事务进行相关操作获取锁,窗口 b 查询当前持有的锁。

--窗口 a
postgres=# begin;
BEGIN

--窗口 b
postgres=# select relation::regclass tab_name,mode from pg_locks where relation = 't'::regclass;
 tab_name | mode
----------+------
(0 rows)

上述可看到开启事务未进行任何操作时,未持锁。

--窗口 a
postgres=# begin;
BEGIN
postgres=*# select * from t;     -->新执行的操作
 a
---
 1
(1 row)

--窗口 b
postgres=# select relation::regclass tab_name,mode from pg_locks where relation = 't'::regclass;
 tab_name |      mode
----------+-----------------
 t        | AccessShareLock       -->新增的锁
(1 row)

上述可看到事务中进行 select 操作时,持有了 ACCESS SHARE 锁。

--窗口 a
postgres=# begin;
BEGIN
postgres=*# select * from t;
 a
---
 1
(1 row)

postgres=*# select * from t for update;     -->新执行的操作
 a
---
 1
(1 row)
--窗口 b
postgres=# select relation::regclass tab_name,mode from pg_locks where relation = 't'::regclass;
 tab_name |      mode
----------+-----------------
 t        | AccessShareLock
 t        | RowShareLock                    -->新增的锁
(2 rows)

上述可看到事务中进行 select for update 操作时,持有了 ROW SHARE 锁。

--窗口 a
postgres=# begin;
BEGIN
postgres=*# select * from t;
 a
---
 1
(1 row)

postgres=*# select * from t for update;
 a
---
 1
(1 row)

postgres=*# update t set a = 2 where a = 1;     -->新执行的操作
UPDATE 1
--窗口 b
postgres=# select relation::regclass tab_name,mode from pg_locks where relation = 't'::regclass;
 tab_name |       mode
----------+------------------
 t        | AccessShareLock
 t        | RowShareLock
 t        | RowExclusiveLock                    -->新增的锁
(3 rows)

上述可看到事务中进行 update 操作时,持有了 ROW EXCLUSIVE 锁。

--窗口 a
postgres=# begin;
BEGIN
postgres=*# select * from t;
 a
---
 1
(1 row)

postgres=*# select * from t for update;
 a
---
 1
(1 row)

postgres=*# update t set a = 2 where a = 1;     
UPDATE 1
postgres=*# create index idx_t_a on t(a);      -->新执行的操作
CREATE INDEX

--窗口 b
postgres=# select relation::regclass tab_name,mode from pg_locks where relation = 't'::regclass;
 tab_name |       mode
----------+------------------
 t        | AccessShareLock
 t        | RowShareLock
 t        | RowExclusiveLock
 t        | ShareLock                          -->新增的锁
(4 rows)

上述可看到事务中进行 create index 操作时,持有了 SHARE 锁。

--窗口 a
postgres=# begin;
BEGIN
postgres=*# select * from t;
 a
---
 1
(1 row)

postgres=*# select * from t for update;
 a
---
 1
(1 row)

postgres=*# update t set a = 2 where a = 1;     
UPDATE 1
postgres=*# create index idx_t_a on t(a);      
CREATE INDEX
postgres=*# alter table t add b int;          -->新执行的操作
ALTER TABLE

--窗口 b
postgres=# select relation::regclass tab_name,mode from pg_locks where relation = 't'::regclass;
 tab_name |       mode
----------+------------------
 t        | AccessShareLock
 t        | RowShareLock
 t        | RowExclusiveLock
 t        | ShareLock
 t        | AccessExclusiveLock                -->新增的锁
(5 rows)

上述可看到事务中进行 alter table 操作时,持有了 ACCESS EXCLUSIVE 锁。

2.2 行级锁

  除了表级锁以外,还有行级锁,两个事务不能在相同的行上持有冲突的锁(一个事务的不同子事务除外)。行级锁不影响数据查询,它们只阻塞对同一行的写入者和加锁者。行级锁在事务结束时或保存点回滚的时候释放,就像表级锁一样。行级锁冲突矩阵如下,空白表示两种锁可相互兼容,X 表示两种锁相互冲突。
在这里插入图片描述

  • FOR UPDATE:FOR UPDATE 会导致由 SELECT 语句检索到的行被锁定,就好像它们要被更新。这可以阻止它们被其他事务锁定、修改或者删除,一直到当前事务结束。也就是说其他尝试 UPDATE、DELETE、SELECT FOR UPDATE、SELECT FOR NO KEY UPDATE、SELECT FOR SHARE 或者 SELECT FOR KEY SHARE 将被阻塞,直到当前事务结束。反过来,SELECT FOR UPDATE 将等待已经在相同行上运行以上这些命令的并发事务,并且接着锁定并且返回被更新的行(或者没有行,因为行可能已被删除)。不过,在一个 REPEATABLE READ 或 SERIALIZABLE 事务中,如果一个要被锁定的行在事务开始后被更改,将会抛出一个错误。
  • FOR NO KEY UPDATE:行为与 FOR UPDATE 类似,不过获得的锁较弱,这种锁将不会阻塞尝试在相同行上获得锁的 SELECT FOR KEY SHARE 命令。任何不获取 FOR UPDATE 锁的 UPDATE 也会获得这种锁模式。
  • FOR SHARE:行为与 FOR NO KEY UPDATE 类似,不过它在每个检索到的行上获得一个共享锁而不是排他锁。一个共享锁会阻塞其他事务在这些行上执行 UPDATE、DELETE、SELECT FOR UPDATE 或者 SELECT FOR NO KEY UPDATE,但是它不会阻止它们执行 SELECT FOR SHARE 或者 SELECT FOR KEY SHARE。
  • FOR KEY SHARE:行为与 FOR SHARE 类似,不过锁较弱,SELECT FOR UPDATE 会被阻塞,但是 SELECT FOR NO KEY UPDATE 不会被阻塞。一个键共享锁会阻塞其他事务执行修改键值的 DELETE 或者 UPDATE,但不会阻塞其他 UPDATE,也不会阻止 SELECT FOR NO KEY UPDATE、SELECT FOR SHARE或者 SELECT FOR KEY SHARE。

示例
窗口 a 在事务中执行操作,窗口 b 对同一对象执行操作,查看是否冲突。

--窗口 a
postgres=# begin;
BEGIN
postgres=*# select * from t for update;
 a
---
 1
(1 row)

--窗口 b
postgres=# select * from t for update;
^CCancel request sent
ERROR:  canceling statement due to user request
CONTEXT:  while locking tuple (0,1) in relation "t"
postgres=# select * from t for no key update;
^CCancel request sent
ERROR:  canceling statement due to user request
CONTEXT:  while locking tuple (0,1) in relation "t"
postgres=#
postgres=# select * from t for share;
^CCancel request sent
ERROR:  canceling statement due to user request
CONTEXT:  while locking tuple (0,1) in relation "t"
postgres=#
postgres=# select * from t for key share;
^CCancel request sent
ERROR:  canceling statement due to user request
CONTEXT:  while locking tuple (0,1) in relation "t"

上述可看到 for update 行锁同其他所有行锁冲突。

--窗口 a
postgres=# begin;
BEGIN
postgres=*# select * from t for key share;
 a
---
 1
(1 row)

--窗口 b
postgres=# select * from t for update;
^CCancel request sent
ERROR:  canceling statement due to user request
CONTEXT:  while locking tuple (0,1) in relation "t"
postgres=#
postgres=# select * from t for no key update;
 a
---
 1
(1 row)

postgres=# select * from t for share;
 a
---
 1
(1 row)

postgres=# select * from t for key share;
 a
---
 1
(1 row)

上述可看到 for key share 行锁仅同 for update 行锁冲突。

2.3 页级锁

  除了表级别和行级别的锁以外,页面级别的共享/排他锁被用来控制对共享缓冲池中表页面的读/写。 这些锁在行被抓取或者更新后马上被释放。应用开发者通常不需要关心页级锁,我们在这里提到它们只是为了完整。

2.4 死锁

  显式锁定的使用可能会增加死锁的可能性,死锁是指两个(或多个)事务相互持有对方想要的锁。例如,如果事务 1 在表 A 上获得一个排他锁,同时试图获取一个在表 B 上的排他锁, 而事务 2 已经持有表 B 的排他锁,同时却正在请求表 A 上的一个排他锁,那么两个事务就都不能进行下去。PostgreSQL 能够自动检测到死锁情况并且会通过中断其中一个事务从而允许其它事务完成来解决这个问题(具体哪个事务会被中断是很难预测的,而且也不应该依靠这样的预测)。防止死锁的最好方法通常是保证所有使用一个数据库的应用都以一致的顺序在多个对象上获得锁。
示例

--窗口 a
postgres=# begin;
BEGIN
postgres=*# update t1 set a = 2 where a = 1;
UPDATE 1
postgres=*# update t2 set a = 11 where a = 1;
UPDATE 1

--窗口 b
postgres=# begin;
BEGIN
postgres=*# update t2 set a = 2 where a = 1;
UPDATE 1
postgres=*# update t1 set a = 22 where a = 1;
ERROR:  deadlock detected            -->此处触发了死锁自动处理机制,中断了该事务。
DETAIL:  Process 11771 waits for ShareLock on transaction 231938; blocked by process 11547.
Process 11547 waits for ShareLock on transaction 231940; blocked by process 11771.
HINT:  See server log for query details.
CONTEXT:  while updating tuple (0,4) in relation "t1"

2.5 咨询锁

  PostgreSQL 提供了一种方法创建由应用定义其含义的锁。这种锁被称为咨询锁,因为系统并不强迫其使用而是由应用来保证其正确的使用。咨询锁可用于 MVCC 模型不适用的锁定策略,其上限数量由 max_locks_per_transaction 和 max_connections 变量决定。
有两种方法在 PostgreSQL 中获取一个咨询锁:
会话级别:对于每一个完成的锁请求必须有一个相应的解锁请求,直至锁被真正释放。
事务级别:在事务结束时会自动释放它们,并且没有显式的解锁操作。

操作咨询锁的函数:
在这里插入图片描述
在这里插入图片描述

示例
两个窗口同时对一条数据执行删除插入操作时会存在如下问题:

--窗口 a
postgres=# create table t1(id int primary key);
CREATE TABLE
postgres=#
postgres=# insert into t1 values(1);
INSERT 0 1
postgres=#
postgres=# begin;
BEGIN
postgres=*# delete from t1 where id = 1;
DELETE 1
postgres=*# insert into t1 values(1);
INSERT 0 1
postgres=*#

--窗口 b
postgres=# begin;
BEGIN
postgres=*# delete from t1 where id = 1;


DELETE 0    -->窗口 a 事务未提交之前一直等待,窗口 a 事务提交后,显示删除 0 行。
postgres=*# insert into t1 values(1);
ERROR:  duplicate key value violates unique constraint "t1_pkey"
DETAIL:  Key (id)=(1) already exists.   -->插入数据报主键唯一约束错误。

上述情况,就可通过使用咨询锁避免:

--窗口 a
postgres=# begin;
BEGIN
postgres=*# select pg_try_advisory_xact_lock(1);  -->窗口 a 进行操作前获取咨询锁
 pg_try_advisory_xact_lock
---------------------------
 t
(1 row)

postgres=*# delete from t1 where id =1;
DELETE 1
postgres=*# insert into t1 values(1);
INSERT 0 1
postgres=*# commit;
COMMIT

--窗口 b
postgres=# begin;
BEGIN
postgres=*# select pg_try_advisory_xact_lock(1);   --窗口 b 进行操作前获取咨询锁失败,不能进行下一步操作。
 pg_try_advisory_xact_lock
---------------------------
 f
(1 row)

postgres=*# select pg_try_advisory_xact_lock(1);   --窗口 b 在窗口 a 提交事务后获取咨询锁成功,可进行下一步操作。
 pg_try_advisory_xact_lock
---------------------------
 t
(1 row)

postgres=*# delete from t1 where id =1;
DELETE 1
postgres=*# insert into t1 values(1);
INSERT 0 1
postgres=*# commit;
COMMIT
postgres=# select * from t1;
 id
----
  1
(1 row)

三、LOCK 显示锁定

3.1 语法

LOCK [ TABLE ] [ ONLY ] name [ * ] [, ...] [ IN lockmode MODE ] [ NOWAIT ]

其中 lockmode 可以是以下之一:

    ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE
    | SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE

参数说明

name:要锁定的一个现有表的名称(可以是模式限定的)。如果在表名前指定了 ONLY,只有该表会被锁定。如果没有指定了 ONLY,该表和它所有的后代表(如果有)都会被锁定。可选地,在表名后指定 * 来显式地表示把后代表包括在内。命令LOCK TABLE a, b 等效于 LOCK TABLE a; LOCK TABLE b。这些表会被按照在 LOCK TABLE中指定的顺序一个一个被锁定。
lockmode:锁模式指定这个锁和哪些锁冲突。如果没有指定锁模式,那将使用最严格的模式 ACCESS EXCLUSIVE。
NOWAIT:指定 LOCK TABLE 不等待任何冲突锁被释放:如果所指定的锁不能立即获得,那么事务就会中止。

3.2 示例

--在将要执行一次删除操作前在主键表上取一个 SHARE ROW EXCLUSIVE 锁
BEGIN WORK;
LOCK TABLE films IN SHARE ROW EXCLUSIVE MODE;
DELETE FROM films_user_comments WHERE id IN
    (SELECT id FROM films WHERE rating < 5);
DELETE FROM films WHERE rating < 5;
COMMIT WORK;

四、锁问题处理

4.1 排查

--查询持锁
SELECT
lock2.pid as locking_pid,
lock1.pid as locked_pid,
stat1.usename as locked_user,
stat1.query as locked_statement,
stat1.state as state,
stat2.query as locking_statement,
stat2.state as state,
now() - stat1.query_start as locking_duration,
stat2.usename as locking_user
FROM pg_catalog.pg_locks lock1
JOIN pg_catalog.pg_stat_activity stat1 on lock1.pid = stat1.pid
JOIN pg_catalog.pg_locks lock2 on
(lock1.locktype,lock1.database,lock1.relation,
lock1.page,lock1.tuple,lock1.virtualxid,
lock1.transactionid,lock1.classid,lock1.objid,
lock1.objsubid) IS NOT DISTINCT FROM
(lock2.locktype,lock2.DATABASE,
lock2.relation,lock2.page,
lock2.tuple,lock2.virtualxid,
lock2.transactionid,lock2.classid,
lock2.objid,lock2.objsubid)
JOIN pg_catalog.pg_stat_activity stat2 on lock2.pid
= stat2.pid
WHERE NOT lock1.granted AND lock2.granted;

--查询行锁
with    
t_wait as    
(    
  select a.mode,a.locktype,a.database,a.relation,a.page,a.tuple,a.classid,a.granted,   
  a.objid,a.objsubid,a.pid,a.virtualtransaction,a.virtualxid,a.transactionid,a.fastpath,    
  b.state,b.query,b.xact_start,b.query_start,b.usename,b.datname,b.client_addr,b.client_port,b.application_name   
    from pg_locks a,pg_stat_activity b where a.pid=b.pid and not a.granted   
),   
t_run as   
(   
  select a.mode,a.locktype,a.database,a.relation,a.page,a.tuple,a.classid,a.granted,   
  a.objid,a.objsubid,a.pid,a.virtualtransaction,a.virtualxid,a.transactionid,a.fastpath,   
  b.state,b.query,b.xact_start,b.query_start,b.usename,b.datname,b.client_addr,b.client_port,b.application_name   
    from pg_locks a,pg_stat_activity b where a.pid=b.pid and a.granted   
),   
t_overlap as   
(   
  select r.* from t_wait w join t_run r on   
  (   
    r.locktype is not distinct from w.locktype and   
    r.database is not distinct from w.database and   
    r.relation is not distinct from w.relation and   
    r.page is not distinct from w.page and   
    r.tuple is not distinct from w.tuple and   
    r.virtualxid is not distinct from w.virtualxid and   
    r.transactionid is not distinct from w.transactionid and   
    r.classid is not distinct from w.classid and   
    r.objid is not distinct from w.objid and   
    r.objsubid is not distinct from w.objsubid and   
    r.pid <> w.pid   
  )    
),    
t_unionall as    
(    
  select r.* from t_overlap r    
  union all    
  select w.* from t_wait w    
)    
select locktype,datname,relation::regclass,page,tuple,virtualxid,transactionid::text,classid::regclass,objid,objsubid,   
string_agg(   
'Pid: '||case when pid is null then 'NULL' else pid::text end||chr(10)||   
'Lock_Granted: '||case when granted is null then 'NULL' else granted::text end||' , Mode: '||case when mode is null then 'NULL' else mode::text end||' , FastPath: '||case when fastpath is null then 'NULL' else fastpath::text end||' , VirtualTransaction: '||case when virtualtransaction is null then 'NULL' else virtualtransaction::text end||' , Session_State: '||case when state is null then 'NULL' else state::text end||chr(10)||   
'Username: '||case when usename is null then 'NULL' else usename::text end||' , Database: '||case when datname is null then 'NULL' else datname::text end||' , Client_Addr: '||case when client_addr is null then 'NULL' else client_addr::text end||' , Client_Port: '||case when client_port is null then 'NULL' else client_port::text end||' , Application_Name: '||case when application_name is null then 'NULL' else application_name::text end||chr(10)||    
'Xact_Start: '||case when xact_start is null then 'NULL' else xact_start::text end||' , Query_Start: '||case when query_start is null then 'NULL' else query_start::text end||' , Xact_Elapse: '||case when (now()-xact_start) is null then 'NULL' else (now()-xact_start)::text end||' , Query_Elapse: '||case when (now()-query_start) is null then 'NULL' else (now()-query_start)::text end||chr(10)||    
'SQL (Current SQL in Transaction): '||chr(10)||  
case when query is null then 'NULL' else query::text end,    
chr(10)||'--------'||chr(10)    
order by    
  ( case mode    
    when 'INVALID' then 0   
    when 'AccessShareLock' then 1   
    when 'RowShareLock' then 2   
    when 'RowExclusiveLock' then 3   
    when 'ShareUpdateExclusiveLock' then 4   
    when 'ShareLock' then 5   
    when 'ShareRowExclusiveLock' then 6   
    when 'ExclusiveLock' then 7   
    when 'AccessExclusiveLock' then 8   
    else 0   
  end ) desc,   
  (case when granted then 0 else 1 end)  
) as lock_conflict  
from t_unionall   
group by   
locktype,datname,relation,page,tuple,virtualxid,transactionid::text,classid,objid,objsubid;

--查询超过 5s 的长事务
select        
  usename,
  datname,
  state,
  wait_event_type,
  wait_event,
  xact_start,
  now(),query,pid,
  now()-xact_start as time
from 
  pg_stat_activity 
where 
  now()-xact_start>interval '5 sec' 
  and query !~ '^COPY' and state<>'idle' 
order by xact_start;

4.2 解锁

--session消失,事物回退,需要superuser权限,可以关闭所有的后台进程
select pg_terminate_backend(1445);

--session还在,事物回退,只能关闭自己用户下的后台进程     
select pg_cancel_backend(1445);         


--批量取消生成取消的SQL
WITH trans AS
  (SELECT pid
   FROM pg_stat_activity
   WHERE now()-xact_start>interval '10 sec'
     AND query !~ '^COPY'
     AND STATE<>'idle'
   ORDER BY xact_start)
SELECT 'select pg_cancel_backend' || '(' || trans.pid || ');'AS killsql
FROM trans;

WITH trans AS  
  (SELECT pid
   FROM pg_stat_activity
   WHERE now()-xact_start>interval '10 sec'
     AND query !~ '^COPY'
     AND STATE<>'idle'
   ORDER BY xact_start)
SELECT 'select pg_terminate_backend' || '(' || trans.pid || ');'AS killsql
FROM trans;

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机图形学笔记2-Viewing 观测

观测主要解决的问题是如何把物体的三维“模型”变成我们在屏幕所看到的二维“图片”&#xff0c;我们在计算机看到实体模型可以分成这样几步&#xff1a; 相机变换(camera transformation)或眼变换(eye transformation)&#xff1a;想象把相机放在任意一个位置来观测物体&#…

实用上位机--QT

实用上位机–QT 通信协议如下 上位机设计界面 #------------------------------------------------- # # Project created by QtCreator 2023-07-29T21:22:32 # #-------------------------------------------------QT += core gui serialportgreaterThan(QT_MAJOR_V…

LLM - model batch generate 生成文本

一.引言 LLM model 类 generate 支持传递 num_return_sequences 进行批量生成&#xff0c;下面简单介绍下原始模型 generate 和 lora 模型 generate 的代码并给出基于 Baichuan-7B 和 ChatGLM 的批量预测效率。 二.generate 参数 介绍 batch generate 之前&#xff0c;先熟悉…

机器学习-Basic Concept

机器学习(Basic Concept) videopptblog Where does the error come from? 在前面我们讨论误差的时候&#xff0c;我们提到了Average Error On Testing Data是最重要的 A more complex model does not lead to better performance on test data Bias And Variance Bias(偏差) …

四通道本地互联网络(LIN)收发器SIT1024Q

特点&#xff1a; ➢ 兼容“LIN 2.x/ISO 17987-4:2016 (12V)/SAE J2602” 标准&#xff1b; ➢ 兼容 K 线&#xff1b; ➢ 内置过温保护功能&#xff08;热关断&#xff09;&#xff1b; ➢ 内置显性超时功能&#xff1b; ➢ 内置 30kΩ 总线上拉从机电阻&#xff1b; ➢…

微软开测“Moment4”启动包:Win11 23H2要来了

近日&#xff0c; 有用户在Win11最新的7月累积更新中发现&#xff0c;更新文件中已经开始出现了对“Moment4”的引用。 具体来说&#xff0c;在7月累积更新中&#xff0c;微软加入了“Microsoft-Windows-UpdateTargeting-ClientOS-SV2Moment4-EKB”“Microsoft-Windows-23H2Ena…

0101日志-运维-mysql

1 错误日志 错误日志&#xff08;Error Log&#xff09;&#xff1a;错误日志记录了MySQL引擎在运行过程中出现的错误和异常情况。这些错误可能包括启动和关闭问题、数据库崩溃、权限问题等。错误日志对于排查和解决MySQL引擎问题非常有帮助。 改日志默认开启&#xff0c;默认存…

python在不同坐标系中绘制曲线

文章目录 平面直角坐标系空间直角坐标系极坐标地理坐标 平面直角坐标系 回顾我们的数据可视化的学习历程&#xff0c;其实始于笛卡尔坐标系的创建&#xff0c;并由此建立了数与形的对应关系。在笛卡尔坐标系中随便点上一点&#xff0c;这个点天生具备坐标&#xff0c;从而与数…

基于LSTM神经网络的电力负荷预测(Python代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f308;3 Python代码及数据 &#x1f389;4 参考文献 &#x1f4a5;1 概述 前馈神经网络的输出只依赖当前输入&#xff0c;但是在文本、视频、语音等时序数据中&#xff0c;时序数据长度并不固定&#xff0c;前馈神经…

我对排序算法的理解

排序算法一直是一个很困惑我的问题&#xff0c;早在刚开始接触 数据结构的时候&#xff0c;这个地方就很让我不解。就是那种&#xff0c;总是感觉少了些什么的感觉。一开始&#xff0c;重新来过&#xff0c;认真来学习这一部分&#xff0c;也总是学着学着就把概念记住了。过了一…

词典项目练习

思维导图 客户端 #include "head.h" //用户提示界面 void help_info1() {printf("\t-----------------------------------------------\n");printf("\t| HENRY 在线辞典 |\n");printf("\t|版本:0.0.1 …

官方实锤!AMD真的已经有了大小核:不搞Intel那一套

Intel 12代酷睿开始引入大小核混合架构&#xff0c;多核跑分提升立竿见影&#xff0c;在游戏、渲染等场景中也有很好的辅助作用&#xff0c;但因为大核心、小核心基于完全不同的架构&#xff0c;需要复杂的系统、软件调度配合&#xff0c;也直接导致失去了AVX-512指令集。 AMD也…

解决多线程环境下单例模式同时访问生成多个实例

如何满足单例&#xff1a;1.构造方法是private、static方法、if语句判断 ①、单线程 Single类 //Single类&#xff0c;定义一个GetInstance操作&#xff0c;允许客户访问它的唯一实例。GetInstance是一个静态方法&#xff0c;主要负责创建自己的唯一实例 public class LazySi…

浅析hooks,复杂前端业务解题之道

hooks 大势所趋 2019年年初&#xff0c;react 在 16.8.x 版本正式具备了 hooks 能力&#xff0c;同年6月&#xff1b;尤雨溪在 vue/github-issues 里提出了关于 vue3 Component API 的提案&#xff08;vue hooks的基础&#xff09;。在Vue3的组合式API出现后&#xff0c;githu…

VS2017配置Qt开发环境

VS2017配置Qt开发环境 安装Qt5.12.11安装Qt插件在VS2017中进行设置参考教程 安装Qt5.12.11 安装Qt插件 在VS2017中进行设置 参考教程 # Qt下载地址 https://download.qt.io/ # Qt安装 https://blog.csdn.net/jjxcsdn/article/details/125432165?spm1001.2014.3001.5506 # VS2…

【LeetCode】解码方法(动态规划)

解码方法 题目描述算法流程编程代码代码优化 链接: 解码方法 题目描述 算法流程 编程代码 class Solution { public:int numDecodings(string s) {int n s.size();vector<int> dp(n);dp[0] s[0] ! 0;if(n 1) return dp[0];if(s[1] < 9 && s[1] > 1) d…

Packet Tracer – 使用 TFTP 服务器升级思科 IOS 映像。

Packet Tracer – 使用 TFTP 服务器升级思科 IOS 映像。 地址分配表 设备 接口 IP 地址 子网掩码 默认网关 R1 F0/0 192.168.2.1 255.255.255.0 不适用 R2 G0/0 192.168.2.2 255.255.255.0 不适用 S1 VLAN 1 192.168.2.3 255.255.255.0 192.168.2.1 TFTP …

Neo4j文档阅读笔记-Installation and Launch Guide

安装&#xff08;Windows&#xff09; ①找到下载好的Neo4j Desktop文件&#xff0c;然后双击进行安装&#xff1b; ②安装Neo4j Desktop根据下一步进行安装。 启动 ①激活 打开Neo4j Desktop应用程序后&#xff0c;将激活码输入到“Activation Key”窗口中。 ②创建数据库…

牛客网Verilog刷题——VL44

牛客网Verilog刷题——VL44 题目题目解析答案 题目 如图所示为两种状态机中的一种&#xff0c;请根据状态转移图写出代码&#xff0c;状态转移线上的0/0等表示的意思是过程中data/flag的值。 要求&#xff1a; 1、 必须使用对应类型的状态机 2、 使用二段式描述方法 注意rs…

远程医疗技术的变革

目录 1.远程医疗的概念 2.远程医疗的发展历史 3.远程医疗的靠谱性 4.远程医疗的潜在危害 1.远程医疗的概念 远程医疗是一种通过通信技术&#xff0c;使医生和患者能够在不同地点进行医疗咨询和治疗的形式。它利用视频通话、电话、在线聊天和其他远程通信工具来实现远程诊断…