|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
多道程序设计:分离进程为独立的功能0 n$ T) {" q) i$ e l( v
' F4 t/ x8 p( O0 m. L% Y3 ~
% p; ?. g2 Q1 NUnix的最具特点的程序模块化技法就是将大型程序分解成多个协作进程。
. R/ \: D0 _+ _# }$ T! p% K4 R: I' b% {% r3 Q
) X0 Z1 W9 U$ W0 i! A5 T Z
Unix提倡把程序分解成更简单的子进程,并考虑接口:/ S6 z( e( s* R9 q) ~
降低进程生成的开销。
4 }2 x0 e$ g) q- W5 i' o0 ]提供方法简化进程间通信。
; X+ p4 j! Q; B$ W! N4 ~提倡使用能由管道和套接字传递的简单、透明的文本数据格式。
5 M3 V/ w o) s+ T6 |+ ~" T/ J% n f
2 j: O# O3 l0 g9 ]' n$ r" n- ~ [0 V, {) Y4 J$ N2 M. q
真正的挑战不是协议语法而是协议逻辑:协议设计既要有充分的表达能力,又能防范死锁。' S3 F) ^6 A/ e( c! v' m
% A5 i4 K3 c' C9 B1 F& i$ x
3 M1 d! Z, T- a6 _( D9 l9 [从性能调整中分离复杂度控制
; W0 @, b; D, p4 J# L# ~$ f
( ?. \7 ^9 i3 N. a( s! Q
$ N# d& C! [: M1 \5 ?' [+ f" c在开发出可以把全局复杂度降至最低程度的干净体系之前,关注性能问题便是过早优化。: m9 k# I0 q7 R* {% n) R$ j4 P# m1 A: I
' Y; z* X- t6 S2 u! e: T m
/ y% D. o3 m. I8 r9 ]# E% U
线程提高了复杂度,应尽量少用线程。
& S; l, j/ u5 x1 S& }. ~9 @! F: O+ {. U6 A O& h8 h" H
. n Y) V0 w- D9 } I将程序划分为多个协作进程的另一重要原因是提高安全性:仅信任较少的代码,而让大部分操作都运行在用户级。
. _1 T+ S7 R2 G8 X" B8 x! W) ~0 u2 f9 _) S' e# l/ C9 R
6 l6 g: @) n! A7 n$ j7 [Unix IPC方法
* B* J( B8 c* `: o2 C8 ~+ K8 n' z. I9 ~7 l5 }5 f6 \
3 R7 {4 S5 H* D/ Y' j9 U* d1 把任务转给专门程序。
W: Y; m; u- v0 S, z0 [5 l; W7 b1 ^& R( j9 n' Q0 ^
: l! U/ d e. Z廉价的进程生成使得程序间协作变得可能,通过调用专门程序来完成专门任务;$ Z6 x- f. ]: b8 ^
C库popen可以用来向专门程序传递数据或读取专门程序的返回结果;: f3 e: u G& [1 g; S( ]! j
专门程序运行期间并不需要与父进程交互。! A+ _) z, Z0 y
' b1 h4 R6 ]8 v2 P+ [# j
( M5 W' o8 C9 v. ]
示例:" `- V0 b F8 V$ R
mutt:调用专门的编辑器。
$ K. o8 a) I0 I: _1 C( W D+ T6 R8 W/ w4 S9 r
6 v( ~, S1 K( @& u
2 管道、重定向、过滤器5 G ?6 t* N' |0 u& W/ a" @
& A# p0 Y8 w0 V4 J
4 _3 w* M- w3 n2 B
管道: |把一个程序的输出连接到另外一个程序的输入;单向性;管道中所有程序并发执行;匿名管道,命名管道(为命名套接字取代)。# Z _9 j; A+ n. n# _# y# L
重定向:> <
$ `5 ~: h( o$ Cpic2graph:调用现有工具的管线。* D% z4 f9 {$ k7 O6 u9 j
dc和bc:相互组合完成问题。
3 I" }2 [! k1 d2 G& s' U' qfetchmail:不能使用,因为管道的单向性;不能发出反馈信息。" S$ u" |) o3 a6 g9 _& h
' h6 U$ a$ I r/ w( } Z4 D- S; T1 P
& c+ `8 d9 Z( o) U3 包装器. e+ x) u- {# ~5 J# F {. y( ]
脚本中封装命令的固定参数
0 L- c7 Y2 Q7 N* P- ]& }2 P. W$ g6 b7 w
' o, g# ]6 X, s; ?! S4 ~( g
4 安全性包装器1 F# l; X: g1 \0 I: U7 L$ r
9 d+ J+ t5 S; q/ s. C: F5 a
: ]4 |' L$ U! Y7 D f* q安全性包装器:调用专门程序检查某类凭证,然后根据返回结果执行后一个程序;
$ l4 @ {. h9 vbernstein链与管道类似;只不过每个继发阶段的程序取代了前一阶段的程序,而不是与之并行。; ~2 S7 s6 a$ k" H
6 |: |; c7 B2 y C! `
+ r5 l: @! P+ g! s. q
5 从进程! t: `6 O; y$ U" X/ q; S
. y6 _# v, z0 i* [' k8 N5 w7 `# b
- Z# i/ g9 y% W; Y9 ^主从通信很复杂,只有在协议无关轻重。
& R6 @, n) t: g4 w; h' D
' a" S; q3 L* q" \2 A! G% d; _, \; c4 j3 m: s; a2 d; O
6 对等进程间通信
7 B, j* r2 g! p9 f' t2 o: Z8 u# ~3 H8 n+ Z
' B0 u2 q) ~5 J- B# B" n$ d' m+ x临时文件:简单,灵活,但容易引起名字冲突,提前中断会造成问题;文件容易被修改,安全问题;
+ }9 e3 f# Z) K$ e- _信号:软中断,SIGHUP一般被用作重启初始化,而用SIGTERM作为正常退出的信号;0 ^5 _9 Q o ^' C2 R
pidfile:守护进程只允许一个实例运行,则可作为文件锁使用。
9 q/ T1 Y6 E! i+ @# rfetchmail信号:唤醒已经存在的进程或者新建进程来获取邮件。+ n+ Y5 D6 Q9 q* R7 F- @# s [
5 o4 |# [/ a4 H( O; u1 a/ |( B& i _' Z. t! H9 R
套接字:双向IPC
, m! i7 L- o$ L/ |. m$ oPostgreSQL:客户端和服务器端分开。( d1 P( D/ v% h5 J& S
0 [3 \1 T: R' z7 Q, p5 p0 y2 Q# T B6 Y" r3 h! P2 T
共享内存:速度快,只用在同一机器上。mmap,将文件映射到内存。自己处理竞争和死锁;避免通过网络栈复制数据的开销。
7 B. N l# Q, U) p0 X5 `! s6 \/ E- b0 C3 h) F
# o9 |$ `5 s) [要避免的问题和方法
4 Q& ?1 \* |# @: J3 X! k0 b0 l
! e/ r4 b: V/ ?. o5 n4 [4 y" Z+ B$ _$ o1 Y- A' a6 x# n
复杂的结构比文本流难以处理。RPC提供了丰富接口,但恰恰将问题复杂化了。) u' {/ T2 Z+ a
文本流:性能损失是线程的,但可通过硬件升级来补偿。! }( U, c2 R- ^- @, M, m o
XML-RPC和SOAP综合了文本流和RPC方法的优点。 `$ G: |9 o8 t' f' y
$ y, b& w6 [! m6 M4 A; ^3 o3 f
4 N# e/ H& w3 J# Z2 C5 K2 v线程; X7 { K7 L5 H. G
3 M) Y* E- A( m% m/ E2 C
9 a# G6 L) L, ] F2 J% e局部变量共享全局内存使得需要加入竞争和临界区的控制,同时bug也会增多。
+ I+ ~' X3 h, D- ~5 n( L$ N时序依赖问题; d Z- C& q/ X/ K9 h% _2 E
尽管线程没有进程上下文切换的开销,但锁定共享数据结构的开销同样昂贵。
& Q& |; p! ?2 o6 ?% E客户端/服务器划分:由服务器集中管理所有资源争用,降低了复杂性,也有利于适应分布式计算。
0 F4 M ]2 d/ D0 {) @# a把线程、远程过程调用接口和重量级的面向对象设计结合使用特别危险。
0 p, L5 ?" n8 C6 v. g
, p- s6 y$ ]. l( ?" E0 u2 _: f% V7 \
6 e. X, f9 _2 @* X; U
1 z5 {; R+ D% _! P& r: p真实世界里的编程其实就是管理复杂度的问题。能够管理复杂度的工具都是好东西。但当这些工具不是控制而是增加复杂度的时候,最好扔掉,从零开始。* i, { @: `; L4 s
# t# `: g! f' s# @/ @) r6 b1 f1 o/ D' Z- o/ I
" S3 Q" Y7 k$ ?9 S. `9 {& f
; K1 k; D' i5 u6 i
$ i- q+ |1 J4 N3 K. h) Z Y- V |
|