【进程代数学习笔记】4:[CSP]进程间的通道通信,管道与活锁避免

2023-12-09 13:59

本文主要是介绍【进程代数学习笔记】4:[CSP]进程间的通道通信,管道与活锁避免,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 记号

1.1 通道和数据

同系统分析与验证课上学的Channel system记号类似,CSP中用序偶 c . v c.v c.v(参见笔记一的2.14)表示在通道 c c c上传送数据 v v v。则进程 P P P能够在通道 c c c上通信的数据记为:
α c ( P ) = { v ∣ c . v ∈ α P } \alpha c(P) = \{v \ | \ c.v \in \alpha P \} αc(P)={v  c.vαP}

c h a n n e l ( ) channel() channel() m e s s a g e ( ) message() message()分别表示取通道名和取数据:
c h a n n e l ( c . v ) = c m e s s a g e ( c . v ) = v channel(c.v) = c \\ message(c.v) = v channel(c.v)=cmessage(c.v)=v

1.2 数据上通道

一进程将数据 v ∈ α c ( P ) v \in \alpha c(P) vαc(P)发送到通道 c c c上,接下来执行 P P P,记为:
( c ! v → P ) = ( c . v → P ) (c!v \to P) = (c.v \to P) (c!vP)=(c.vP)

1.3 从通道取数据

一进程从通道 c c c取下一个数据 x x x,并根据收到的 x x x的不同决定接下来的执行 P ( x ) P(x) P(x),记为:
( c ? x → P ( x ) ) = ( y : { y ∣ c h a n n e l ( y ) = c } → P ( m e s s a g e ( y ) ) ) (c?x \to P(x)) = (y: \{y \ | \ channel(y) = c \} \to P(message(y)) \ ) (c?xP(x))=(y:{y  channel(y)=c}P(message(y)) )

式中 y y y表示通道 c c c上传递 m e s s a g e ( y ) message(y) message(y)的序偶,如 c . 7 c.7 c.7


例如,拷贝一比特数据的进程 C O P Y B I T COPYBIT COPYBIT,可理解成从 i n in in通道取 v ∈ { 0 , 1 } v \in \{0,1\} v{0,1},再发送到 o u t out out通道上:
C O P Y B I T = μ X ⋅ ( i n ? x → ( o u t ! x → X ) ) COPYBIT = \mu X \cdot (in?x \to (out!x \to X)) COPYBIT=μX(in?x(out!xX))

其中 α i n ( C O P Y B I T ) = α o u t ( C O P Y B I T ) = { 0 , 1 } \alpha in(COPYBIT) = \alpha out (COPYBIT) = \{0,1\} αin(COPYBIT)=αout(COPYBIT)={0,1}

1.4 进程间使用通道通信

这里要注意和系统分析课使用的记号不同,这里就是用普通的并发" ∣ ∣ || "记号, P ∣ ∣ Q P||Q PQ P P P发送数据到通道 c c c(即 c ! v c!v c!v),而 Q Q Q从通道 c c c上取数据(即 c ? x c?x c?x)时,两进程就会发送通信。例如发送的数据是7,即是说 P P P执行的动作是 c ! 7 c!7 c!7 Q Q Q推进的动作是 c ? 7 → Q ( 7 ) c?7 \to Q(7) c?7Q(7)

总是要求通道两侧的进程在通道上传值的字母表一致,即 α c ( P ) = α c ( Q ) \alpha c(P) = \alpha c(Q) αc(P)=αc(Q),不妨记为 α c \alpha c αc

通道通信中的字母表是关于通道名称的字母表!

2 几个例子

在CSP里的通信模型中,进程的下标表达了进程状态的互递归关系,其指示的是进程收到的通道中的值(还未传出去的那些)。

2.1 数据处理单元

这个例子用于理解在引入通道通信后,进程如何表达数据处理单元。这里是直接将数据乘以2:
D O U B L E = μ X ⋅ ( l e f t ? x → r i g h t ! ( x + x ) → X ) DOUBLE = \mu X \cdot (left?x \to right!(x+x) \to X) DOUBLE=μX(left?xright!(x+x)X)

2.2 序列拆分

l e f t left left通道一次性读入长度为80的数据,从 r i g h t right right通道一次输出一个(队头):
α l e f t = { s ∣ s ∈ α r i g h t ∗ ∧ # x = 80 } U N P A C K = P ⟨ ⟩ P ⟨ ⟩ = l e f t ? s → P s P ⟨ x ⟩ = r i g h t ! x → P ⟨ ⟩ P ⟨ x ⟩ ⌢ s = r i g h t ! x → P s \begin{aligned} \alpha left &= \{s \ | \ s\in \alpha right^* \wedge \#x = 80 \} \\ UNPACK &= P_{\langle \rangle} \\ \\ P_{\langle \rangle} & = left?s \to P_s \\ P_{\langle x \rangle} & = right!x \to P_{\langle \rangle} \\ P_{\langle x \rangle^\smallfrown s} & = right!x \to P_s \end{aligned} αleftUNPACKPPxPxs={s  sαright#x=80}=P=left?sPs=right!xP=right!xPs

2.3 序列合并

l e f t left left通道每次读入一个数据,到125个时从 r i g h t right right通道一次性输出:
α r i g h t = { s ∣ s ∈ α l e f t ∗ ∧ # s = 125 } P A C K = P ⟨ ⟩ P s = r i g h t ! s → P ⟨ ⟩ i f # s = 125 P s = l e f t ? x → P s ⌢ ⟨ x ⟩ i f # s < 125 \begin{aligned} \alpha right & = \{s \ | \ s \in \alpha left^* \wedge \#s = 125 \} \\ PACK & = P_{\langle \rangle} \\ \\ P_s & = right!s \to P_{\langle \rangle} & if \ \#s=125 \\ P_s & = left?x \to P_{s^\smallfrown \langle x \rangle} & if \ \#s<125 \end{aligned} αrightPACKPsPs={s  sαleft#s=125}=P=right!sP=left?xPsxif #s=125if #s<125

2.4 子串替换

这个例子有点编译器的味道,就是把" ∗ ∗ ** “输出成” ↑ \uparrow ",其它都不变,显然要在输入了一个" ∗ * "时检查下一个输入:
α l e f t = α r i g h t − { " ↑ " } S Q U A S H = μ X ⋅ l e f t ? x → i f x ≠ " ∗ " t h e n ( r i g h t ! x → X ) e l s e l e f t ? y → i f y = " ∗ " t h e n ( r i g h t ! " ↑ " → X ) e l s e ( r i g h t ! " ∗ " → r i g h t ! y → X ) ) \begin{aligned} \alpha left & = \alpha right - \{"\uparrow"\} \\ SQUASH & = \mu X \cdot left?x \to \\ if \ x & \neq "*" \ then \ (right!x \to X) \\ else \ &left?y \to \\ & if \ y="*" \ then \ (right!"\uparrow" \to X) \\ & else \ (right!"*" \to right!y \to X)) \end{aligned} αleftSQUASHif xelse =αright{""}=μXleft?x="" then (right!xX)left?yif y="" then (right!""X)else (right!""right!yX))

2.4 可选输入

一个双输入管道,但每次只选其一,然后就原样输出的进程:
α l e f t 1 = α l e f t 2 = α r i g h t M E R G E = ( l e f t 1 ? x → r i g h t ! x → M E R G E ∣ l e f t 2 ? x → r i g h t ! x → M E R G E ) \begin{aligned} \alpha left1 = & \alpha left2 = \alpha right \\ MERGE =& (left1?x \to right!x \to MERGE \\ & | \ left2?x \to right!x \to MERGE) \end{aligned} αleft1=MERGE=αleft2=αright(left1?xright!xMERGE left2?xright!xMERGE)

显然,输出可以是两个输入序列的任一Interleaving。

2.5 一位寄存器

总是可以读入一个数据将当前数据覆盖掉,或者输出寄存的数据而不会因输出导致丢失数据:
α l e f t = α r i g h t V A R = l e f t ? x → V A R x V A R x = ( l e f t ? y → V A R y ∣ r i g h t ! x → V A R x ) \begin{aligned} \alpha left & = \alpha right \\ VAR & = left?x \to VAR_x \\ VAR_x & = (left?y \to VAR_y \ | \ right!x \to VAR_x) \end{aligned} αleftVARVARx=αright=left?xVARx=(left?yVARy  right!xVARx)

2.6 多参数计算单元

u p up up通道读入prod,从 l e f t left left通道读入sum,计算 s u m + v × p r o d sum+v \times prod sum+v×prod的进程:
N O D E ( v ) = μ X ⋅ ( u p ? s u m → l e f t ? p r o d → d o w n ! ( s u m + v × p r o d ) → X ) NODE(v) = \mu X \cdot (up?sum \to left?prod \to down!(sum+v \times prod) \to X) NODE(v)=μX(up?sumleft?proddown!(sum+v×prod)X)

2.7 无限容量的队列

注意2.72.8模拟栈和队列都是在用进程模拟,而不是在用通道模拟。通道本身就是一个队列,在CSP里忽视通道的容量。

读入元素放到队尾,出队时去除队头元素:
B U F F E R = P ⟨ ⟩ P ⟨ ⟩ = l e f t ? x → P ⟨ x ⟩ P ⟨ x ⟩ ⌢ s = ( l e f t ? y → P ⟨ x ⟩ ⌢ s ⌢ ⟨ y ⟩ ∣ r i g h t ! x → P x ) \begin{aligned} BUFFER & = P_{\langle \rangle} \\ \\ P_{\langle \rangle} & = left?x \to P_{\langle x \rangle} \\ P_{\langle x \rangle^\smallfrown s} & = (left?y \to P_{\langle x \rangle^\smallfrown s^\smallfrown \langle y \rangle} \ | \ right!x \to P_x) \end{aligned} BUFFERPPxs=P=left?xPx=(left?yPxsy  right!xPx)

2.8 无限容量的栈

读入元素放到栈顶,出栈时去除栈顶元素:
S T A C K = P ⟨ ⟩ P ⟨ ⟩ = l e f t ? x → P ⟨ x ⟩ P ⟨ x ⟩ ⌢ s = ( l e f t ? y → P ⟨ y ⟩ ⌢ ⟨ x ⟩ ⌢ s ∣ r i g h t ! x → P x ) \begin{aligned} STACK & = P_{\langle \rangle} \\ \\ P_{\langle \rangle} & = left?x \to P_{\langle x \rangle} \\ P_{\langle x \rangle^\smallfrown s} & = (left?y \to P_{\langle y \rangle^\smallfrown \langle x \rangle^\smallfrown s} \ | \ right!x \to P_x) \end{aligned} STACKPPxs=P=left?xPx=(left?yPyxs  right!xPx)

3 通道满足规范(specification)

3.1 简述

定义迹 t r tr tr中在有关通道 c c c的所有动作的值 v v v组成的迹:
t r ↓ c = m e s s a g e ∗ ( t r ↾ α c ) tr \downarrow c = message^*(tr \upharpoonright \alpha c) trc=message(trαc)

输入通道和输出通道的迹之间往往可以存在序关系(一方是另一方的前缀):
t r ↓ r i g h t ≤ t r ↓ l e f t tr \downarrow right \leq tr \downarrow left trrighttrleft

简写成 r i g h t ≤ l e f t right \leq left rightleft。所以:
s ≤ n t = ( s ≤ t ∧ # t ≤ # s + n ) s \leq^n t = (s \leq t \wedge \# t \leq \# s+n) snt=(st#t#s+n)
这表示,通道 s s s(的trace)是通道 t t t(的trace)的前缀,并且 t t t(的trace)最多比 s s s(的trace)长n。这可导出如下性质:

  • s ≤ 0 t ≡ ( s = t ) s \leq^0 t \equiv (s = t) s0t(s=t)
    最多长0说明一样长,又是前缀说明它们的trace就是一样的。
  • s ≤ n t ∧ t ≤ m u ⇒ s ≤ n + m u s \leq^n t \wedge t \leq^m u \Rightarrow s \leq^{n+m} u snttmusn+mu
    这是由前缀的传递性和不等式的合并。
  • s ≤ t ≡ ∃ n ⋅ s ≤ n t s \leq t \equiv \exists n \cdot s \leq^n t stnsnt
    前缀关系总是会有长度关系的界。
3.2 例子

1.3中的 C O P Y B I T COPYBIT COPYBIT满足:
C O P Y B I T s a t r i g h t ≤ 1 l e f t COPYBIT \ sat \ right \leq^1 left COPYBIT sat right1left

右边总是左边的前缀,且左边比右边最多长1,仅当刚输入还没开始输出时取等号。


2.1中的 D O U B L E DOUBLE DOUBLE满足:
D O U B L E s a t r i g h t ≤ 1 d o u b l e ∗ ( l e f t ) DOUBLE \ sat \ right \leq^1 double^*(left) DOUBLE sat right1double(left)

这在本质上和上一个是一样的,式中" d o u b l e ∗ ( ) double^*() double()"仅仅是一个将传入的trace中每个数字乘2的符号变换而已。


2.2中的 U N P A C K UNPACK UNPACK满足:
U N P A C K s a t r i g h t ≤ 80 ⌢ / l e f t UNPACK \ sat \ right \leq^{80} \smallfrown / left UNPACK sat right80/left

其中 ⌢ / \smallfrown / /后接一个序列,作用是将其中的所有元素连接成一个合乎规格的普通trace:
⌢ / ⟨ s 0 , s 1 , . . . , s n − 1 ⟩ = s 0 ⌢ s 1 ⌢ . . . ⌢ s n − 1 \smallfrown / \langle s_0, s_1, ... , s_{n-1} \rangle = s_0^\smallfrown s_1^\smallfrown ... ^\smallfrown s_{n-1} /s0,s1,...,sn1=s0s1...sn1

上面是课本中的写法,意思就是trace里包含trace,实际上在这个例子和下一个例子里都只包含一个 s 0 s_0 s0,这里 # s 0 = 80 \# s_0 = 80 #s0=80,下个例子里 # s 0 = 125 \# s_0 = 125 #s0=125


2.3中的 P A C K PACK PACK满足:
P A C K s a t ( ( ⌢ / r i g h t ≤ 125 l e f t ) ∧ ( # ∗ r i g h t ∈ { 125 } ∗ ) ) PACK \ sat \ (( \smallfrown / right \leq^{125} left) \wedge ( \#^* right \in \{125\}^*)) PACK sat ((/right125left)(#right{125}))

4 通信(Communication)

4.1 简述

进程间可以依靠通道上发送和接受值来实现通信:
在这里插入图片描述
如上图中若 v = 7 v=7 v=7,则进程 Q Q Q也就收到 x = 7 x=7 x=7,然后执行 Q ( 7 ) Q(7) Q(7)

  • L1: ( c ! v → P ) ∣ ∣ ( c ? x → Q ( x ) ) = c ! v → ( P ∣ ∣ Q ( v ) ) (c!v \to P) \ || \ (c?x \to Q(x)) = c!v \to (P \ || \ Q(v)) (c!vP)  (c?xQ(x))=c!v(P  Q(v))
    传递的信息 v v v决定后续动作。

  • L2: ( ( c ! v → P ) ∣ ∣ ( c ? x → Q ( x ) ) ) \ C = ( P ∣ ∣ Q ( v ) ) \ C ((c!v \to P) \ || \ (c?x \to Q(x))) \backslash C = (P \ || \ Q(v)) \backslash C ((c!vP)  (c?xQ(x)))\C=(P  Q(v))\C
    这是将通道上的通讯动作屏蔽掉,其中通道动作集合 C = { c . v ∣ v ∈ α c } C = \{c.v \ | \ v\in \alpha c\} C={c.v  vαc}

4.2 例子

在这里插入图片描述
P = ( l e f t ? x → m i d ! ( x × x ) → P ) Q = ( m i d ? y → r i g h t ! ( 173 × y ) → Q ) \begin{aligned} P & = (left?x \to mid!(x \times x) \to P) \\ Q & = (mid?y \to right!(173 \times y) \to Q) \end{aligned} PQ=(left?xmid!(x×x)P)=(mid?yright!(173×y)Q)

其中, P P P Q Q Q各自满足的规格:
P s a t ( m i d ≤ 1 s q u a r e ∗ ( l e f t ) ) Q s a t ( r i g h t ≤ 1 173 × m i d ) \begin{aligned} P \ & sat \ (mid \leq^1 square^*(left)) \\ Q \ & sat \ (right \leq^1 173 \times mid) \end{aligned} P Q sat (mid1square(left))sat (right1173×mid)

两进程并发,所有满足的规格要取合取:
( P ∣ ∣ Q ) s a t ( r i g h t ≤ 1 173 × m i d ) ∧ ( m i d ≤ 1 s q u a r e ∗ ( l e f t ) ) (P \ || \ Q) \ sat \ (right \leq^1 173 \times mid) \wedge (mid \leq^1 square^*(left)) (P  Q) sat (right1173×mid)(mid1square(left))

从而:
r i g h t ≤ 173 × s q u a r e ∗ ( l e f t ) right \leq 173 \times square^*(left) right173×square(left)

5 管道(Pipes)

5.1 简述

管道是一系列进程的顺序组合,这些进程之间通信的通道被屏蔽掉,即外部无法看到管道内部的具体通信过程,如将4.1中两进程间的通信过程隐藏:
在这里插入图片描述
记为 P > > Q P>>Q P>>Q,管道的字母表:
α ( P > > Q ) = α l e f t ( P ) ∪ α r i g h t ( P ) \begin{aligned} \alpha(P>>Q) & = \alpha left(P) \cup \alpha right(P) \\ \end{aligned} α(P>>Q)=αleft(P)αright(P)

5.2 例子

通过组合不同的进程,可以构造出具有各式各样功能的管道。

  • X1: Q U A D R U P L E = D O U B L E > > D O U B L E QUADRUPLE = DOUBLE >> DOUBLE QUADRUPLE=DOUBLE>>DOUBLE
    将输入数据放大四倍的管道。

  • X2: U N P A C K > > P A C K UNPACK >> PACK UNPACK>>PACK
    80到125的序列长度转换器。

  • X3: U N P A C K > > S Q U A S H > > P A C K UNPACK >> SQUASH >> PACK UNPACK>>SQUASH>>PACK
    类似于X2,只是还要在转换过程中将" ∗ ∗ ** “过滤为” ↑ \uparrow "。

  • X4: U N P A C K > > B U F F E R > > P A C K UNPACK >> BUFFER >> PACK UNPACK>>BUFFER>>PACK
    类似于X2,相当于加了一个缓冲区,使得管道的输入和输出可以异步工作。

  • X5: C O P Y > > U N P A C K > > P A C K > > C O P Y COPY >> UNPACK >> PACK >> COPY COPY>>UNPACK>>PACK>>COPY
    注意,这里 C O P Y COPY COPY是拷贝任意一个数据,不必是一个二进制位。这个管道类似于X4,相当于在左右添加一个容量为1的缓冲区,使得输入输出可以异步工作。

  • X6: C O P Y > > C O P Y COPY >> COPY COPY>>COPY
    容量为2的缓冲区,最多在输出前预接受2个数据。

5.3 管道的操作规则
  • L1: P > > ( Q > > R ) = ( P > > Q ) > > R P>>(Q>>R) = (P>>Q)>>R P>>(Q>>R)=(P>>Q)>>R
    管道满足结合律(因为最终总是要把内部全屏蔽完),但不满足交换律。

  • L2: ( r i g h t ! v → P ) > > ( l e f t ? y → Q ( y ) ) = P > > Q ( y ) (right!v \to P)>>(left?y \to Q(y))=P>>Q(y) (right!vP)>>(left?yQ(y))=P>>Q(y)
    P P P出和从 Q Q Q进的动作在 P > > Q P>>Q P>>Q中对外屏蔽,但这一动作会影响 Q Q Q使其接下来执行 Q ( v ) Q(v) Q(v)

  • L3: ( r i g h t ! v → P ) > > ( r i g h t ! w → Q ) = r i g h t ! w → ( ( r i g h t ! v → P ) > > Q ) (right!v \to P)>>(right!w \to Q)=right!w \to ((right!v \to P)>>Q) (right!vP)>>(right!wQ)=right!w((right!vP)>>Q)
    P P P出和从 Q Q Q出的动作,其中前者(从 P P P出)是管道内部的动作,要在内部执行。

  • L4: ( l e f t ? x → P ( x ) ) > > ( l e f t ? y → Q ( y ) ) = l e f t ? x → ( P ( x ) > > ( l e f t ? y → Q ( y ) ) ) (left?x \to P(x))>>(left?y \to Q(y))=left?x \to (P(x)>>(left?y \to Q(y))) (left?xP(x))>>(left?yQ(y))=left?x(P(x)>>(left?yQ(y)))
    P P P进和从 Q Q Q进的动作,其中后者(从 Q Q Q进)是管道内部的动作,要在内部执行。

5.4 管道的活锁(Livelock)现象

活锁是比递归程序出现 S T O P STOP STOP更坏的情况,其根本原因是管道屏蔽了内部动作,如:
P = ( r i g h t ! 1 → P ) Q = ( l e f t ? x → Q ) \begin{aligned} P & = (right!1 \to P) \\ Q & = (left?x \to Q) \end{aligned} PQ=(right!1P)=(left?xQ)
进程 P P P不断输出1,而进程 Q Q Q不断接受输入,两者连成管道 ( P > > Q ) (P>>Q) (P>>Q)后,从外部看来整个管道是静止的,其实内部在不停消耗计算资源。

这是一个最纯粹的活锁例子,这样的活锁现象会抢占正常工作的动作,如:
P = ( r i g h t ! 1 → P ∣ l e f t ? x → P 1 ( x ) ) Q = ( l e f t ? x → Q ∣ r i g h t ! 1 → Q 1 ) \begin{aligned} P & = (right!1 \to P \ | \ left?x \to P1(x)) \\ Q & = (left?x \to Q \ | \ right!1 \to Q1) \end{aligned} PQ=(right!1P  left?xP1(x))=(left?xQ  right!1Q1)

它们组成的管道 ( P > > Q ) (P>>Q) (P>>Q)会出现 P P P发送 Q Q Q接收的白白消耗计算资源的情况,则正常工作的部分( P P P接收、 Q Q Q发送)就被抢占了。

5.5 避免活锁(free of livelock)

如果进程 P P P不能无限的输出(而不受输入限制),那么就称 P P P是left-guarded的。其数学表达是:
∃ f ⋅ P s a t ( # r i g h t ≤ f ( l e f t ) ) \exists f\cdot P \ sat \ (\#right \leq f(left)) fP sat (#rightf(left))

其中, # r i g h t \#right #right是指到任何时刻为止输出的数据长度。而 f f f是指一个函数,将到该时刻为止的输入映射到自然数集中。这是在要求任何时刻输出的数据长度都有一个上界,而这个上界取决于输入数据。例如"输入1个数据,随后输出10个该数据"这样的进程就是left-guarded,例如可以取到这样一个 f f f
f ( l e f t ) = 11 × # l e f t f(left) = 11\times \#left f(left)=11×#left

从而总有 # r i g h t ≤ f ( l e f t ) \#right \leq f(left) #rightf(left) 10 t ≤ 11 t 10t \leq 11t 10t11t是成立的( t t t是经历的时刻)。

同理可以定义right-guarded,略。

  • L1:如果任何用到 P P P的递归进程在 P P P左边都有guarded的输入,那么 P P P是left-guared的。
  • L2:如果 P P P是left-guarded的,那么 ( P > > Q ) (P>>Q) (P>>Q)不会发生活锁。
  • L3:如果 Q Q Q是right-guarded的,那么 ( P > > Q ) (P>>Q) (P>>Q)不会发生活锁。

这篇关于【进程代数学习笔记】4:[CSP]进程间的通道通信,管道与活锁避免的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/473958

相关文章

C#如何优雅地取消进程的执行之Cancellation详解

《C#如何优雅地取消进程的执行之Cancellation详解》本文介绍了.NET框架中的取消协作模型,包括CancellationToken的使用、取消请求的发送和接收、以及如何处理取消事件... 目录概述与取消线程相关的类型代码举例操作取消vs对象取消监听并响应取消请求轮询监听通过回调注册进行监听使用Wa

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57