|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
多道程序设计:分离进程为独立的功能
, T4 e3 J D% i' I; `* o: r j3 e {) C/ b# o& k7 G. o( s; m
, W: ?8 Z* q! C+ y/ s8 `+ c
Unix的最具特点的程序模块化技法就是将大型程序分解成多个协作进程。7 N7 Y Q+ C6 W7 q* X/ Z
0 U8 v! |6 ^" g5 N! I* e
+ G3 f( R4 k# ]3 W6 SUnix提倡把程序分解成更简单的子进程,并考虑接口:# X K$ o* A. r9 V5 c
降低进程生成的开销。
( T' @, D. t( x提供方法简化进程间通信。' O2 ^% c8 f- a( S1 a! Y
提倡使用能由管道和套接字传递的简单、透明的文本数据格式。
! l9 y# o, R6 g' A& Y
( l. e& |, Z$ z0 |" w' L3 R4 `9 T6 e; L- U$ V& k6 o; z, e" e( [
真正的挑战不是协议语法而是协议逻辑:协议设计既要有充分的表达能力,又能防范死锁。
$ o1 u. U. Q& k3 e2 X9 O; Q V8 L% e9 [: [: i# X" O
, t* G- B' d. D& G6 |" ~1 O
从性能调整中分离复杂度控制( W4 K; o; Z7 B, @) z
8 F8 d9 ]: g) _& \: c1 e% Y
" f7 q+ [9 e" }& t
在开发出可以把全局复杂度降至最低程度的干净体系之前,关注性能问题便是过早优化。# C1 l) b+ f9 l( C
1 B. U' I! q9 }, s, X/ d# p3 G) h5 O$ v) c0 v3 D
线程提高了复杂度,应尽量少用线程。- `& r! o, N" {5 j; e6 U2 T/ ]6 [0 W
$ x* n' h/ ^8 R
$ h& u3 r; }6 |2 B将程序划分为多个协作进程的另一重要原因是提高安全性:仅信任较少的代码,而让大部分操作都运行在用户级。+ @+ O+ e" u, ?, Y7 n
+ W" U) y, ^5 X* }' @; W* s! L* g* d8 h/ |$ B/ H
Unix IPC方法$ ~) S- Z) x# Z8 O6 l7 ^: Q' Q
i* J H3 O) s! E: V( ^8 i
x" i/ z) Y C6 [
1 把任务转给专门程序。
( B6 ]5 I, a0 H2 t) a: Z% ]; c- F% M* ^9 A
: A5 ]0 ?9 h5 h/ R# N
廉价的进程生成使得程序间协作变得可能,通过调用专门程序来完成专门任务;* `' j9 P% `8 U3 _
C库popen可以用来向专门程序传递数据或读取专门程序的返回结果;+ V& x6 [2 H C# f
专门程序运行期间并不需要与父进程交互。
: C1 \; _% S: b: Z; C$ r. `0 h4 o3 E0 u( g6 j1 |
/ R9 j$ M+ K* K$ n0 k! T示例:
# n* \$ } p5 h5 D- R& M( D2 S$ L8 Qmutt:调用专门的编辑器。
% z; _8 w, y! k5 ]3 t5 S! D
5 m+ O& N! P; H9 _+ Z1 W* P) g9 D. _8 @+ r0 ]
2 管道、重定向、过滤器
/ E7 T# |7 z- S. l& @* M! h ?8 r& O* @; U( a7 M% K
. Q9 b' L, Z5 j1 B' o5 S4 J' {1 V! S管道: |把一个程序的输出连接到另外一个程序的输入;单向性;管道中所有程序并发执行;匿名管道,命名管道(为命名套接字取代)。
' G! n' | ]2 w1 _% t8 B6 N/ D重定向:> <
+ o, m( O6 ?' v: x2 e. ]3 C% Fpic2graph:调用现有工具的管线。
+ Q0 @9 S/ G) S/ ]. Pdc和bc:相互组合完成问题。$ `$ ?1 o1 A1 q! B
fetchmail:不能使用,因为管道的单向性;不能发出反馈信息。) `/ W1 t) X) X" ~. Z( J
, M6 o6 n* N9 ^8 y/ _
* W. g. U4 x% H( p4 h
3 包装器
5 W; z& e `. b/ Y脚本中封装命令的固定参数0 r, j' W: w0 Z5 v; N- {- ?
% L3 c4 O! u* T6 d1 w, i/ R0 `4 o& U, ?
4 安全性包装器3 v5 ^5 p& T$ v. s
- H/ I, x5 A. f* |1 \" j3 j4 }) _- }& z; p& D# F) `5 J0 S
安全性包装器:调用专门程序检查某类凭证,然后根据返回结果执行后一个程序;, W6 ~9 G2 ?# n9 F4 Q8 C( R+ L9 O
bernstein链与管道类似;只不过每个继发阶段的程序取代了前一阶段的程序,而不是与之并行。
8 V A" U3 ~( ]8 u c+ V. _; ~5 v) W: a; |. Q" W
, u4 ?( Q' s) p4 r* |. S
5 从进程, f4 Z- L3 t* t! Y$ y" e5 x
4 \3 L* W1 W; W) C2 H; K
# L7 ?5 I' W) Y
主从通信很复杂,只有在协议无关轻重。 h- h1 O f0 u$ b/ V0 E% A/ P
4 Q5 O8 t0 T6 _
9 Z9 s s8 ]+ T" E0 y- k) n
6 对等进程间通信
2 n$ J1 c' b* ?( \
5 f& j( [: {0 @, f8 R9 X# W0 Q M1 k( }) D' }$ `: z: Y& Z- m9 |
临时文件:简单,灵活,但容易引起名字冲突,提前中断会造成问题;文件容易被修改,安全问题;
: L9 ?' Y2 Z2 Z2 C0 Q- _+ O& b信号:软中断,SIGHUP一般被用作重启初始化,而用SIGTERM作为正常退出的信号;
0 H2 M" }: |# M$ Hpidfile:守护进程只允许一个实例运行,则可作为文件锁使用。
2 d- n- G% c2 @; [9 }) gfetchmail信号:唤醒已经存在的进程或者新建进程来获取邮件。* H9 O9 E: T; E' z1 E8 w) k
6 I% I3 p2 G8 W, x6 K% E% O
( O* V. K) ^ F5 D' O$ ^ Y套接字:双向IPC3 p( c! [( m6 v2 e. r* W9 x* A( w
PostgreSQL:客户端和服务器端分开。& u2 I$ x- A7 g, z# i; k
0 ]# E- E" }! [
3 w8 {% M- n. R* N; _2 G
共享内存:速度快,只用在同一机器上。mmap,将文件映射到内存。自己处理竞争和死锁;避免通过网络栈复制数据的开销。
) Q1 d* E5 b+ ^9 w" a6 w0 s3 c' {
3 L- O) c) ~/ x7 ^3 Z1 R
. z9 r, x$ C6 \$ N! G. S要避免的问题和方法
. |+ _. ?( Z- w' {& a. k4 D+ M( \# K, O/ ~5 a4 ^' ?$ Z
0 n' M# E) S7 H. t0 T复杂的结构比文本流难以处理。RPC提供了丰富接口,但恰恰将问题复杂化了。9 U% d! g9 p; O0 d) H
文本流:性能损失是线程的,但可通过硬件升级来补偿。9 [* i7 h3 e/ X2 `" X' _+ \/ u
XML-RPC和SOAP综合了文本流和RPC方法的优点。1 w' I5 `* v! h9 p! U
4 d" O' K( l6 U+ D
6 f- Z: B9 G: y线程
2 n6 o; C% l0 r0 P9 I% z8 Y3 Y; L: Z: ~- Z1 K
- o* l/ {4 m; f( B% ]9 G8 P
局部变量共享全局内存使得需要加入竞争和临界区的控制,同时bug也会增多。
, o+ \4 I1 n3 H时序依赖问题$ z( C' ?7 ]. c
尽管线程没有进程上下文切换的开销,但锁定共享数据结构的开销同样昂贵。
1 a: x" _- x) W8 y3 H3 {客户端/服务器划分:由服务器集中管理所有资源争用,降低了复杂性,也有利于适应分布式计算。
/ k* V8 C3 G+ t$ S' l# | `把线程、远程过程调用接口和重量级的面向对象设计结合使用特别危险。
. i7 l5 e9 L" ]2 C5 |5 {- M j/ w& c+ P0 H+ N
7 U1 _) M$ Q. x" q8 y' S! e
' H5 s- {% ]; f# u/ g/ b
5 T1 i# i( S, ^3 F, c9 m真实世界里的编程其实就是管理复杂度的问题。能够管理复杂度的工具都是好东西。但当这些工具不是控制而是增加复杂度的时候,最好扔掉,从零开始。' _: m1 E0 C S. I% ?9 G+ O2 u
; G7 a, u! X {' m) Y- C( L8 t7 ]
% B8 r( J8 @0 G4 L- ~: I- D% h& f+ s' d; M
) m7 r5 O4 J# \9 |5 x# X8 W$ ? |
|