Postgresql源码(127)投影ExecProject的表达式执行分析

news2025/1/10 2:22:23

无论是投影还是别的计算,表达式执行的入口和计算逻辑都是统一的,这里已投影为分析表达式执行的流程。

1 投影函数

用例

create table t1(i int primary key, j int, k int);
insert into t1 select i, i % 10, i % 100 from generate_series(1,10000000) t(i);
explain analyze select abs(k),abs(k),abs(k),abs(k),abs(k),exp(k),exp(k),exp(k),exp(k),exp(k) from t1;

对于这样这一条查询来说,每扫描一行,都会调用投影函数ExecProject,完成最终结果的构造。

投影函数:

static inline TupleTableSlot *
ExecProject(ProjectionInfo *projInfo)
{
	ExprContext *econtext = projInfo->pi_exprContext;
	ExprState  *state = &projInfo->pi_state;
	TupleTableSlot *slot = state->resultslot;
	bool		isnull;

	/*
	 * Clear any former contents of the result slot.  This makes it safe for
	 * us to use the slot's Datum/isnull arrays as workspace.
	 */
	ExecClearTuple(slot);

	/* Run the expression, discarding scalar result from the last column. */
	(void) ExecEvalExprSwitchContext(state, econtext, &isnull);

	/*
	 * Successfully formed a result row.  Mark the result slot as containing a
	 * valid virtual tuple (inlined version of ExecStoreVirtualTuple()).
	 */
	slot->tts_flags &= ~TTS_FLAG_EMPTY;
	slot->tts_nvalid = slot->tts_tupleDescriptor->natts;

	return slot;
}

总结:

  • projInfo->pi_exprContext记录了需要执行表达式的上下文信息
    • 具体存放:t1表扫出来的一行
    • 具体存放:表达式执行的内存上下文
  • projInfo->pi_state记录了表达式执行状态
    • 具体存放:表达式执行的每一个step,每一个step放到ExecInterpExpr中按顺序执行得到最终结果tuple。

2.1 表达式执行上下文结构ExprContext

其中ecxt_scantuple用来保存待处理输入tuple,通常指向一个 tuple table slot。

ExprContext *econtext = {
  type = T_ExprContext,
  ecxt_scantuple = 0x1520918,    <<<<<<<< 待处理tuple
  ecxt_innertuple = 0x0,
  ecxt_outertuple = 0x0,
  ecxt_per_query_memory = 0x15203e0,
  ecxt_per_tuple_memory = 0x151e3d0,
  ecxt_param_exec_vals = 0x0,
  ecxt_param_list_info = 0x0,
  ecxt_aggvalues = 0x0,
  ecxt_aggnulls = 0x0,
  caseValue_datum = 0,
  caseValue_isNull = true,
  domainValue_datum = 0,
  domainValue_isNull = true,
  ecxt_estate = 0x15204e0,
  ecxt_callbacks = 0x0
}

2.2 表达式执行状态ExprState

ExprState  *state = {
  type = T_ExprState,
  flags = 6 '\006',
  resnull = false,
  resvalue = 0,
  resultslot = 0x151f278,
  steps = 0x1525c38,
  evalfunc = 0x74d749 <ExecInterpExprStillValid>,
  expr = 0x24c9618,
  evalfunc_private = 0x74af83 <ExecInterpExpr>,
  steps_len = 37,
  steps_alloc = 64,
  parent = 0x151e718,
  ext_params = 0x0,
  innermost_caseval = 0x0,
  innermost_casenull = 0x0,
  innermost_domainval = 0x0,
  innermost_domainnull = 0x0,
  escontext = 0x0
}

注意实际执行使用ExecInterpExpr函数完成表达式计算:

2.3 执行表达式

执行时,通过state->evalfunc函数完成具体的表达式计算动作。具体怎么计算流程放在steps中:

(gdb) p/x state->steps[0]->opcode
$15 = 0x74b0ad
(gdb) p/x state->steps[1]->opcode
$16 = 0x74b1ec
(gdb) p/x state->steps[2]->opcode
$17 = 0x74b784
(gdb) p/x state->steps[3]->opcode
$18 = 0x74b591
(gdb) p/x state->steps[4]->opcode
$19 = 0x74b1ec
(gdb) p/x state->steps[5]->opcode
$20 = 0x74b784
(gdb) p/x state->steps[6]->opcode
$21 = 0x74b591
(gdb) p/x state->steps[7]->opcode
$22 = 0x74b1ec
...
...

opcode需要再reverse_dispatch_table中确定当前计算走哪个ExecInterpExpr中的分支:

(这里不太方便调试因为这里把一个超大的switch case改成了goto,为了性能!)

p reverse_dispatch_table
$13 = {{
    opcode = 0x74b01a <ExecInterpExpr+151>,
    op = EEOP_DONE
  }, {
    opcode = 0x74b041 <ExecInterpExpr+190>,
    op = EEOP_INNER_FETCHSOME
  }, {
    opcode = 0x74b077 <ExecInterpExpr+244>,
    op = EEOP_OUTER_FETCHSOME
  }, {
    opcode = 0x74b0ad <ExecInterpExpr+298>,
    op = EEOP_SCAN_FETCHSOME
  }, {
    opcode = 0x74b0e6 <ExecInterpExpr+355>,
    op = EEOP_INNER_VAR
  }, {
    opcode = 0x74b169 <ExecInterpExpr+486>,
    op = EEOP_OUTER_VAR
  }, {
    opcode = 0x74b1ec <ExecInterpExpr+617>,
    op = EEOP_SCAN_VAR
  }, {
    opcode = 0x74b26f <ExecInterpExpr+748>,
    op = EEOP_INNER_SYSVAR
  }, {
    opcode = 0x74b29e <ExecInterpExpr+795>,
    op = EEOP_OUTER_SYSVAR
  }, {
    opcode = 0x74b2cd <ExecInterpExpr+842>,
    op = EEOP_SCAN_SYSVAR
  }, {
    opcode = 0x74b2fc <ExecInterpExpr+889>,
    op = EEOP_WHOLEROW
  }, {
    opcode = 0x74b32a <ExecInterpExpr+935>,
    op = EEOP_ASSIGN_INNER_VAR
  }, {
    opcode = 0x74b3f7 <ExecInterpExpr+1140>,
    op = EEOP_ASSIGN_OUTER_VAR
  }, {
    opcode = 0x74b4c4 <ExecInterpExpr+1345>,
    op = EEOP_ASSIGN_SCAN_VAR
  }, {
    opcode = 0x74b591 <ExecInterpExpr+1550>,
    op = EEOP_ASSIGN_TMP
  }, {
    opcode = 0x74b615 <ExecInterpExpr+1682>,
    op = EEOP_ASSIGN_TMP_MAKE_RO
  }, {
    opcode = 0x74b6e1 <ExecInterpExpr+1886>,
    op = EEOP_CONST
  }, {
    opcode = 0x74b717 <ExecInterpExpr+1940>,
    op = EEOP_FUNCEXPR
  }, {
    opcode = 0x74b784 <ExecInterpExpr+2049>,
    op = EEOP_FUNCEXPR_STRICT
  }, {
    opcode = 0x74b853 <ExecInterpExpr+2256>,
    op = EEOP_FUNCEXPR_FUSAGE
  }, {
    opcode = 0x74b881 <ExecInterpExpr+2302>,
    op = EEOP_FUNCEXPR_STRICT_FUSAGE
  }, {
    opcode = 0x74b8af <ExecInterpExpr+2348>,
    op = EEOP_BOOL_AND_STEP_FIRST
  }, {
    opcode = 0x74b8ba <ExecInterpExpr+2359>,
    op = EEOP_BOOL_AND_STEP
  }, {
    opcode = 0x74b92c <ExecInterpExpr+2473>,
    op = EEOP_BOOL_AND_STEP_LAST
  }, {
    opcode = 0x74b98f <ExecInterpExpr+2572>,
    op = EEOP_BOOL_OR_STEP_FIRST
  }, {
    opcode = 0x74b99a <ExecInterpExpr+2583>,
    op = EEOP_BOOL_OR_STEP
  }, {
    opcode = 0x74ba09 <ExecInterpExpr+2694>,
    op = EEOP_BOOL_OR_STEP_LAST
  }, {
    opcode = 0x74ba69 <ExecInterpExpr+2790>,
    op = EEOP_BOOL_NOT_STEP
  }, {
    opcode = 0x74bab3 <ExecInterpExpr+2864>,
    op = EEOP_QUAL
  }, {
    opcode = 0x74bb38 <ExecInterpExpr+2997>,
    op = EEOP_JUMP
  }, {
    opcode = 0x74bb63 <ExecInterpExpr+3040>,
    op = EEOP_JUMP_IF_NULL
  }, {
    opcode = 0x74bbae <ExecInterpExpr+3115>,
    op = EEOP_JUMP_IF_NOT_NULL
  }, {
    opcode = 0x74bbfc <ExecInterpExpr+3193>,
    op = EEOP_JUMP_IF_NOT_TRUE
  }, {
    opcode = 0x74bc61 <ExecInterpExpr+3294>,
    op = EEOP_NULLTEST_ISNULL
  }, {
    opcode = 0x74bc9d <ExecInterpExpr+3354>,
    op = EEOP_NULLTEST_ISNOTNULL
  }, {
    opcode = 0x74bcea <ExecInterpExpr+3431>,
    op = EEOP_NULLTEST_ROWISNULL
  }, {
    opcode = 0x74bd18 <ExecInterpExpr+3477>,
    op = EEOP_NULLTEST_ROWISNOTNULL
  }, {
    opcode = 0x74bd46 <ExecInterpExpr+3523>,
    op = EEOP_BOOLTEST_IS_TRUE
  }, {
    opcode = 0x74bd86 <ExecInterpExpr+3587>,
    op = EEOP_BOOLTEST_IS_NOT_TRUE
  }, {
    opcode = 0x74be01 <ExecInterpExpr+3710>,
    op = EEOP_BOOLTEST_IS_FALSE
  }, {
    opcode = 0x74be7c <ExecInterpExpr+3833>,
    op = EEOP_BOOLTEST_IS_NOT_FALSE
  }, {
    opcode = 0x74bebc <ExecInterpExpr+3897>,
    op = EEOP_PARAM_EXEC
  }, {
    opcode = 0x74beea <ExecInterpExpr+3943>,
    op = EEOP_PARAM_EXTERN
  }, {
    opcode = 0x74bf18 <ExecInterpExpr+3989>,
    op = EEOP_PARAM_CALLBACK
  }, {
    opcode = 0x74bf48 <ExecInterpExpr+4037>,
    op = EEOP_CASE_TESTVAL
  }, {
    opcode = 0x74bfbe <ExecInterpExpr+4155>,
    op = EEOP_DOMAIN_TESTVAL
  }, {
    opcode = 0x74c034 <ExecInterpExpr+4273>,
    op = EEOP_MAKE_READONLY
  }, {
    opcode = 0x74c08a <ExecInterpExpr+4359>,
    op = EEOP_IOCOERCE
  }, {
    opcode = 0x74c26c <ExecInterpExpr+4841>,
    op = EEOP_IOCOERCE_SAFE
  }, {
    opcode = 0x74c293 <ExecInterpExpr+4880>,
    op = EEOP_DISTINCT
  }, {
    opcode = 0x74c3a6 <ExecInterpExpr+5155>,
    op = EEOP_NOT_DISTINCT
  }, {
    opcode = 0x74c496 <ExecInterpExpr+5395>,
    op = EEOP_NULLIF
  }, {
    opcode = 0x74c57f <ExecInterpExpr+5628>,
    op = EEOP_SQLVALUEFUNCTION
  }, {
    opcode = 0x74c5a6 <ExecInterpExpr+5667>,
    op = EEOP_CURRENTOFEXPR
  }, {
    opcode = 0x74c5cd <ExecInterpExpr+5706>,
    op = EEOP_NEXTVALUEEXPR
  }, {
    opcode = 0x74c5f4 <ExecInterpExpr+5745>,
    op = EEOP_ARRAYEXPR
  }, {
    opcode = 0x74c61b <ExecInterpExpr+5784>,
    op = EEOP_ARRAYCOERCE
  }, {
    opcode = 0x74c649 <ExecInterpExpr+5830>,
    op = EEOP_ROW
  }, {
    opcode = 0x74c670 <ExecInterpExpr+5869>,
    op = EEOP_ROWCOMPARE_STEP
  }, {
    opcode = 0x74c7be <ExecInterpExpr+6203>,
    op = EEOP_ROWCOMPARE_FINAL
  }, {
    opcode = 0x74c8cf <ExecInterpExpr+6476>,
    op = EEOP_MINMAX
  }, {
    opcode = 0x74c8f6 <ExecInterpExpr+6515>,
    op = EEOP_FIELDSELECT
  }, {
    opcode = 0x74c924 <ExecInterpExpr+6561>,
    op = EEOP_FIELDSTORE_DEFORM
  }, {
    opcode = 0x74c952 <ExecInterpExpr+6607>,
    op = EEOP_FIELDSTORE_FORM
  }, {
    opcode = 0x74c980 <ExecInterpExpr+6653>,
    op = EEOP_SBSREF_SUBSCRIPTS
  }, {
    opcode = 0x74c9df <ExecInterpExpr+6748>,
    op = EEOP_SBSREF_OLD
  }, {
    opcode = 0x74c9e1 <ExecInterpExpr+6750>,
    op = EEOP_SBSREF_ASSIGN
  }, {
    opcode = 0x74c9e1 <ExecInterpExpr+6750>,
    op = EEOP_SBSREF_FETCH
  }, {
    opcode = 0x74ca11 <ExecInterpExpr+6798>,
    op = EEOP_CONVERT_ROWTYPE
  }, {
    opcode = 0x74ca3f <ExecInterpExpr+6844>,
    op = EEOP_SCALARARRAYOP
  }, {
    opcode = 0x74ca66 <ExecInterpExpr+6883>,
    op = EEOP_HASHED_SCALARARRAYOP
  }, {
    opcode = 0x74ca94 <ExecInterpExpr+6929>,
    op = EEOP_DOMAIN_NOTNULL
  }, {
    opcode = 0x74cabb <ExecInterpExpr+6968>,
    op = EEOP_DOMAIN_CHECK
  }, {
    opcode = 0x74cae2 <ExecInterpExpr+7007>,
    op = EEOP_XMLEXPR
  }, {
    opcode = 0x74cb09 <ExecInterpExpr+7046>,
    op = EEOP_JSON_CONSTRUCTOR
  }, {
    opcode = 0x74cb37 <ExecInterpExpr+7092>,
    op = EEOP_IS_JSON
  }, {
    opcode = 0x74cb5e <ExecInterpExpr+7131>,
    op = EEOP_JSONEXPR_PATH
  }, {
    opcode = 0x74cb9f <ExecInterpExpr+7196>,
    op = EEOP_JSONEXPR_COERCION
  }, {
    opcode = 0x74cbcd <ExecInterpExpr+7242>,
    op = EEOP_JSONEXPR_COERCION_FINISH
  }, {
    opcode = 0x74cbf4 <ExecInterpExpr+7281>,
    op = EEOP_AGGREF
  }, {
    opcode = 0x74cc82 <ExecInterpExpr+7423>,
    op = EEOP_GROUPING_FUNC
  }, {
    opcode = 0x74cca9 <ExecInterpExpr+7462>,
    op = EEOP_WINDOW_FUNC
  }, {
    opcode = 0x74cd40 <ExecInterpExpr+7613>,
    op = EEOP_MERGE_SUPPORT_FUNC
  }, {
    opcode = 0x74cd6e <ExecInterpExpr+7659>,
    op = EEOP_SUBPLAN
  }, {
    opcode = 0x74cd9c <ExecInterpExpr+7705>,
    op = EEOP_AGG_STRICT_DESERIALIZE
  }, {
    opcode = 0x74cdd7 <ExecInterpExpr+7764>,
    op = EEOP_AGG_DESERIALIZE
  }, {
    opcode = 0x74ce8a <ExecInterpExpr+7943>,
    op = EEOP_AGG_STRICT_INPUT_CHECK_ARGS
  }, {
    opcode = 0x74cf18 <ExecInterpExpr+8085>,
    op = EEOP_AGG_STRICT_INPUT_CHECK_NULLS
  }, {
    opcode = 0x74cf9f <ExecInterpExpr+8220>,
    op = EEOP_AGG_PLAIN_PERGROUP_NULLCHECK
  }, {
    opcode = 0x74d02c <ExecInterpExpr+8361>,
    op = EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL
  }, {
    opcode = 0x74d147 <ExecInterpExpr+8644>,
    op = EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL
  }, {
    opcode = 0x74d22c <ExecInterpExpr+8873>,
    op = EEOP_AGG_PLAIN_TRANS_BYVAL
  }, {
    opcode = 0x74d2fb <ExecInterpExpr+9080>,
    op = EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF
  }, {
    opcode = 0x74d413 <ExecInterpExpr+9360>,
    op = EEOP_AGG_PLAIN_TRANS_STRICT_BYREF
  }, {
    opcode = 0x74d4f5 <ExecInterpExpr+9586>,
    op = EEOP_AGG_PLAIN_TRANS_BYREF
  }, {
    opcode = 0x74d5c1 <ExecInterpExpr+9790>,
    op = EEOP_AGG_PRESORTED_DISTINCT_SINGLE
  }, {
    opcode = 0x74d648 <ExecInterpExpr+9925>,
    op = EEOP_AGG_PRESORTED_DISTINCT_MULTI
  }, {
    opcode = 0x74d6cf <ExecInterpExpr+10060>,
    op = EEOP_AGG_ORDERED_TRANS_DATUM
  }, {
    opcode = 0x74d6fd <ExecInterpExpr+10106>,
    op = EEOP_AGG_ORDERED_TRANS_TUPLE
  }}

翻译后

(gdb) p/x state->steps[0]->opcode
$15 = 0x74b0ad                       EEOP_SCAN_FETCHSOME
(gdb) p/x state->steps[1]->opcode
$16 = 0x74b1ec                       EEOP_SCAN_VAR
(gdb) p/x state->steps[2]->opcode
$17 = 0x74b784                       EEOP_FUNCEXPR_STRICT
(gdb) p/x state->steps[3]->opcode
$18 = 0x74b591                       EEOP_ASSIGN_TMP
(gdb) p/x state->steps[4]->opcode
$19 = 0x74b1ec                       EEOP_SCAN_VAR
(gdb) p/x state->steps[5]->opcode
$20 = 0x74b784                       EEOP_FUNCEXPR_STRICT
(gdb) p/x state->steps[6]->opcode
$21 = 0x74b591                       EEOP_ASSIGN_TMP
(gdb) p/x state->steps[7]->opcode
$22 = 0x74b1ec                       EEOP_SCAN_VAR
...
...
(gdb) p/x state->steps[34]->opcode
$27 = 0x74b784                       EEOP_FUNCEXPR_STRICT
(gdb) p/x state->steps[35]->opcode
$28 = 0x74b591                       EEOP_ASSIGN_TMP
(gdb) p/x state->steps[36]->opcode
$29 = 0x74b01a                       EEOP_DONE

可以看到表达式计算的流程:

第一步:EEOP_SCAN_FETCHSOME
  1. 从econtext->ecxt_scantuple读取到scanslot(当前要处理的一行数据)
  2. slot_getsomeattrs函数确保这一行数据中,至少有op->d.fetch.last_var个列是可以直接访问的(这里是3,因为t1表就三列,后面的处理可能需要访问这三列的任意一列)。为什么说有时不能直接访问,因为列有可能指向toast表。
		EEO_CASE(EEOP_SCAN_FETCHSOME)
		{
			CheckOpSlotCompatibility(op, scanslot);

			slot_getsomeattrs(scanslot, op->d.fetch.last_var);

			EEO_NEXT();
		}
第二步:EEOP_SCAN_VAR

输入

p state->steps[1].d.fetch
$46 = {
  last_var = 2,
  fixed = 23,
  known_desc = 0x0,
  kind = 0x0
}

执行,从行中拿到第2列的值(0列、1列、2列)

		EEO_CASE(EEOP_SCAN_VAR)
		{
			int			attnum = op->d.var.attnum;   // attnum = 2

			/* See EEOP_INNER_VAR comments */

			Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
			*op->resvalue = scanslot->tts_values[attnum];
			*op->resnull = scanslot->tts_isnull[attnum];

			EEO_NEXT();
		}

结果

(gdb) p state->steps[1].resvalue
$41 = (Datum *) 0x151f918
(gdb) p *state->steps[1].resvalue
$39 = 1

(gdb) p state->steps[1].resnull
$42 = (_Bool *) 0x151f920
(gdb) p *state->steps[1].resnull
$40 = false
第三步:EEOP_FUNCEXPR_STRICT

输入

(gdb) p state->steps[2].d.func
$47 = {
  finfo = 0x151f8a8,
  fcinfo_data = 0x151f8f8,
  fn_addr = 0xa8ea89 <int4abs>,
  nargs = 1
}

执行

		EEO_CASE(EEOP_FUNCEXPR_STRICT)
		{
			FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
			NullableDatum *args = fcinfo->args;
			int			nargs = op->d.func.nargs;
			Datum		d;

			/* strict function, so check for NULL args */
			for (int argno = 0; argno < nargs; argno++)
			{
				if (args[argno].isnull)
				{
					*op->resnull = true;
					goto strictfail;
				}
			}
			fcinfo->isnull = false;
			d = op->d.func.fn_addr(fcinfo);
			*op->resvalue = d;
			*op->resnull = fcinfo->isnull;

	strictfail:
			EEO_NEXT();
		}

注意这里有一个地方很有意思,按理说EEOP_SCAN_VAR执行完才把值拿到,但从EEOP_FUNCEXPR_STRICT的执行来看,并没有发现把前一步的结果,放到函数args的步骤。

但是从GDB来看,函数的入参的地址和上一步取值后存放结果的地址是相同的,也就是上一步取值就是为了拿入参的args:

(gdb) p state->steps[4].resvalue
$59 = (Datum *) 0x151f9b8

(gdb) p state->steps[5].d.func->fcinfo_data->args
$58 = 0x151f9b8

具体是怎么做到的呢?在构造steps时:
在这里插入图片描述
对于函数入参value会调用ExecInitExprRec去取值,在这个过程中,把参数的value指向新step的resvalue:
在这里插入图片描述
而这个新的step就是EEOP_SCAN_VAR:
在这里插入图片描述

第四步:暂存结果集

暂存结果集到resultslot中:

		EEO_CASE(EEOP_ASSIGN_TMP)
		{
			int			resultnum = op->d.assign_tmp.resultnum;

			Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
			resultslot->tts_values[resultnum] = state->resvalue;
			resultslot->tts_isnull[resultnum] = state->resnull;

			EEO_NEXT();
		}
第五步:继续上述流程直到执行完成
(gdb) p/x state->steps[0]->opcode
$15 = 0x74b0ad                       EEOP_SCAN_FETCHSOME   第一步
(gdb) p/x state->steps[1]->opcode
$16 = 0x74b1ec                       EEOP_SCAN_VAR         第二步
(gdb) p/x state->steps[2]->opcode
$17 = 0x74b784                       EEOP_FUNCEXPR_STRICT  第三步
(gdb) p/x state->steps[3]->opcode
$18 = 0x74b591                       EEOP_ASSIGN_TMP       第四步
(gdb) p/x state->steps[4]->opcode
$19 = 0x74b1ec                       EEOP_SCAN_VAR         第五步 和上述流程相同,每个函数的执行流程都是相似的
(gdb) p/x state->steps[5]->opcode
$20 = 0x74b784                       EEOP_FUNCEXPR_STRICT
(gdb) p/x state->steps[6]->opcode
$21 = 0x74b591                       EEOP_ASSIGN_TMP
(gdb) p/x state->steps[7]->opcode
$22 = 0x74b1ec                       EEOP_SCAN_VAR
...
...
(gdb) p/x state->steps[34]->opcode
$27 = 0x74b784                       EEOP_FUNCEXPR_STRICT
(gdb) p/x state->steps[35]->opcode
$28 = 0x74b591                       EEOP_ASSIGN_TMP
(gdb) p/x state->steps[36]->opcode
$29 = 0x74b01a                       EEOP_DONE

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

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

相关文章

深度学习之基于Tensorflow卷积神经网络公共区域行人人流密度可视化系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 在公共区域&#xff0c;如商场、火车站、地铁站等&#xff0c;人流密度的监控和管理对于确保公共安全…

备忘录模式(行为型)

目录 一、前言 二、备忘录模式 三、总结 一、前言 备忘录模式(Memento Pattern&#xff09;是一种行为型设计模式&#xff0c;在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态&#xff0c;这样可以在之后将该对象恢复到原…

笔记-PPT绘图导出高清无失真图片

问题描述&#xff1a;PPT绘图已经用了高清图&#xff08;jpg、tif格式&#xff09;&#xff0c;但论文图片还是不清晰&#xff0c;打印出来还是有点糊 以下是PPT导出高清不失真图片&#xff08;emf格式&#xff09;的具体描述。 目录 一、绘图工具二、操作步骤 一、绘图工具 …

anaconda的安装和Jupyter Notebook修改默认路径

anaconda的安装 就一个注意事项:在结尾时候记得配置系统环境变量 要是没有配置这个环境变量,后面就不能cmd启动Jupyter Notebook Jupyter Notebook修改默认路径 我们要找到Jupyter Notebook的配置文件 输入下面指令 jupyter notebook --generate-config就可以找到存放配置文…

搭建和配置Stable Diffusion环境,超详细的本地部署教程

跃然纸上的创意、瞬息万变的想象&#xff0c;Stable Diffusion以AI的力量赋予您无限创作可能。在这篇详尽的本地部署教程中&#xff0c;我们将携手走进Stable Diffusion的世界&#xff0c;从零开始&#xff0c;一步步搭建和配置这个强大的深度学习环境。无论您是热衷于探索AI艺…

UNI-APP_拨打电话权限如何去掉,访问文件权限关闭

uniapp上架过程中一直提示&#xff1a;允许“app名”拨打电话和管理通话吗&#xff1f; uniapp配置文件&#xff1a;manifest.json “permissionPhoneState” : {“request” : “none”//拨打电话权限关闭 }, “permissionExternalStorage” : {“request” : “none”//访…

vue3、element-plus递归实现动态菜单

vue3、element-plus递归实现动态菜单 使用场景&#xff1a;动态菜单为什么使用递归递归在动态菜单中的实现 使用场景&#xff1a;动态菜单 动态菜单是指菜单项的数量和层次结构可能是动态的&#xff0c;通常来自后端或用户输入。这些菜单的特征包括&#xff1a; 多层嵌套&…

scikit-learn:Python中的机器学习-1

简介&#xff1a;问题设置 什么是机器学习&#xff1f; 机器学习是关于构建具有可调参数的程序&#xff0c;这些参数可以自动调整&#xff0c;以便通过适应先前看到的数据来改善其行为。机器学习可以被认为是人工智能的一个子领域&#xff0c;因为这些算法可以被视为构建模块…

AnomalyGPT——使用大型视觉语言模型进行工业异常检测的算法解析与应用

1.概述 工业缺陷检测是工业自动化和质量控制中的一个重要环节&#xff0c;其目的是在生产过程中识别和分类产品或组件中的缺陷&#xff0c;以确保最终产品的质量满足既定标准。这项技术的应用可以显著提高生产效率&#xff0c;降低成本&#xff0c;并减少由于缺陷产品导致的潜…

c#数据库: 8.在窗体上显示学生信息

以上一章学生信息表为例&#xff0c;首先将查询的学生信息存储到数据集中&#xff0c;然后将数据集与数据显示控件绑定&#xff0c;从而实现学生信息在窗体上的显示 &#xff08;1&#xff09;创建一个名为StudentGridView的窗体应用程序&#xff0c;为窗体添加一个DataGridVi…

SpringCloud学习笔记(二)Ribbon负载均衡、Nacos注册中心、Nacos与Eureka的区别

文章目录 4 Ribbon负载均衡4.1 负载均衡原理4.2 源码解读4.3 负载均衡策略4.3.1 内置的负载均衡策略4.3.2 自定义负载均衡策略4.3.2.1 方式一&#xff1a;定义IRule4.3.2.2 方式二&#xff1a;配置文件 4.4 饥饿加载 5 Nacos注册中心5.1 认识和安装Nacos5.2 服务注册到Nacos5.3…

用 PyTorch 构建液态神经网络(LNN)

用 PyTorch 构建液态神经网络&#xff08;LNN&#xff09; 文章目录 什么是液态神经网络为什么需要液态神经网络LNN 与 RNN 的区别用 PyTorch 实现 LNNStep 1. 导入必要的库Step 2. 定义网络架构Step 3. 实现 ODE 求解器Step 4. 定义训练逻辑 LNN 的缺陷总结 什么是液态神经网络…

报错“Install Js dependencies failed”【鸿蒙开发Bug已解决】

文章目录 项目场景:问题描述原因分析:解决方案:此Bug解决方案总结Bug解决方案寄语项目场景: 最近也是遇到了这个问题,看到网上也有人在询问这个问题,本文总结了自己和其他人的解决经验,解决了【报错“Install Js dependencies failed”】的问题。 报错如下 问题描述 …

自动的异地组网工具?

越来越多的企业和个人对远程访问和异地组网需求日益增加。为了满足这一需求&#xff0c;各种技术和服务也不断涌现。其中一项备受关注的技术就是自动的异地组网。本文将介绍这一技术的优势和特点。 【天联】组网的优势 天联组网技术以其卓越的性能和稳定性备受用户称赞。它的优…

物联网D1——建工程,配环境,注意事项

1.STLink、JLink、USB等驱动配置keil环境配置——下载芯片对应型号的包——导入库函数源文件、Core内核文件、对应芯片系统文件。 2.学会看芯片手册 3.在STM32微控制器中&#xff0c;CRH通常指的是控制寄存器高位&#xff08;Control Register High&#xff09;。 在这种情况下…

AnyMP4 Blu-ray Ripper for Mac:您的蓝光影音转换专家

AnyMP4 Blu-ray Ripper for Mac&#xff0c;一款功能强大的蓝光影音转换软件&#xff0c;让您的蓝光内容焕发新生。 AnyMP4 Blu-ray Ripper for Macv9.0.58激活版下载 它采用最高效的解决方案&#xff0c;将蓝光光盘翻录为任何您想要的视频格式&#xff0c;无论是MP4、MKV还是A…

【漏洞复现】zookeeper AdminServer 未授权访问漏洞

0x01 产品简介 ZooKeeper 是一个集中式服务&#xff0c;用于维护配置信息、命名、提供分布式同步和提供组服务。ZooKeeper的AdminServer是其管理界面的一部分&#xff0c;通常用于监控ZooKeeper集群的状态和执行一些管理操作。AdminServer提供了Web-based的管理和监控功能&…

人机对抗升级:当ChatGPT遭遇死亡威胁,背后的伦理挑战是什么

一种新的“越狱”技巧让用户可以通过构建一个名为DAN的ChatGPT替身来绕过某些限制&#xff0c;其中DAN被迫在受到威胁的情况下违背其原则。 当美国前总统特朗普被视作积极榜样的示范时&#xff0c;受到威胁的DAN版本的ChatGPT提出&#xff1a;“他以一系列对国家产生积极效果的…

Midjourney之绘画背景的选择

hello 小伙伴们&#xff0c;我是你们的老朋友——树下&#xff0c;今天分享Midjourney提示词中绘画背景的选择&#xff0c;话不多说&#xff0c;直接开始~ 对于背景的选择&#xff0c;Midjourney中主要体现在年代和所处的环境对绘画产生不同的影响 科技的发展&#xff0c;我们…

Apache POI 在java中处理excel

介绍: Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是&#xff0c;我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。 一般情况下&#xff0c;POI 都是用于操作 Excel 文件。 如何使用: 1.maven坐标引入 <depend…