Unix 最具特点的程序模块化技法: 就是将大型程序分解成为多个协作进程。但是,几乎没有好的实践方法。尽管将程序划分成协作进程带来了全局复杂度的降低,但代价是我们必须更多的关注在进程间传递消息和命令的协议设计和通信各方设计状态机的问题。
Unix为多进程提供的有
降低多进程 生成的开销
提供方法、IO、管道、消息传递、套接字 简化进程通信
提倡使用能有管道、套接字传递的简单、透明的文本数据格式
进程: 为了降低复杂度,而非为了利用并发提升性能。线程: 为了提高性能,然而,线程并不是降低而是提高的全局复杂度。除非万不得已,不要使用线程。
Unix IPC 方法分类
shell调用其他程序,这种情形的要点在于, 专门程序在运行时不需要跟父进程交流,只要任意一方接受了 另外一个程序的输入
管道、重定向、过滤器: 管道线中的所有阶段的程序是并发运行的。注意到这一点很重要,每一段在等待前一段的输出作为输入。管道已经成为老古董,被套接字取代
从进程
对等进程间通讯: 通常意味着数据能够自由的双向流动
临时文件: 文件名字冲突(shell脚本中的管理实在临时文件命中包含’$$’,这个shell变量将被展开为载入shell进程的ID, 从而保证文件名的唯一性)
信号: Unix信号是一种软中断形式,每个信号对接受进程产生默认作用(杀掉它),进程可以声明 信号处理程序,让信号处理程序覆盖默认行为,信号最初被涉及到Unix中,最初是最为操作系统就某些错误或关键事件通知程序的一种方式, 举例来说, SIGHUP信号,会在会话结束时被发送给每一个该指定终端会话启动的程序,例: 在用户键入中断(Ctrl-c)时候, 发送给当前每一个连接键盘的程序,然而,信号经常被用作,守护程序的控制通道,随着信号IPC经常使用的一种技法是所谓的pidfile, 需要信号的程序会向已知的位置写入一个包含进程ID的文件(/var/run)其他程序可以通过该文件来获取PID, 如果守护程序只允许一个实例运行,该pidfile, 也作为隐含的文件锁使用。
套接字: 一种封装网络数据访问的方法, 使用协议族来告诉网络层如何解释套接字的名称, AF_UNIX作为同一台机器上两个进程之间的通信方式.
共享内存: 要求生产者和消费者都必须在一个机器上,但是如果通信进程能够访问同一块物理内存,则共享内存为最快的信息传递方法。需要处理竞争和死锁问题.
要避免的问题和方法
废弃的Unix IPC方法, System V IPC, Steams
远程过程调用(RPC), 最成功的RPC应用,是网络文件系统,都是那些在应用定义域上本来就只涉及很少量简单数据类型的应用。支持RPC的理由通常是, 允许更丰富的接口,但是更不简介,(Unix 强烈赞成使用透明,可显的接口, 这是Unix文化不断坚持文本协议的动力)。RPC往往更多延迟的原因有: a: 无法准确估算一个指令调用会涉及到多少数据的列表和散列,b:RPC模型鼓励程序员忽视网络交易成本,造成网络时间消耗
线程: 共享全局内存,在这个共享地址空间管理竞争和临界区的任务相当困难,增加整体复杂度。随着锁定机制复杂度的增加意外交互作用所造成的竞争和死锁机会也会增加。锁定共享数据结构以防止互相干涉的开销非常昂贵,最关键的难题在于,各个系统中实现的标准,没有标准,所以不可能进行移植
线程的使用应该是最后一招而不是第一招,如果能够使用优先的共享内存和信号量,使用SIGIO的一部I/O,poll,select 而不是使用线程,那就保持简单
线程、远程过程调用、重量级的面向对象设计结合使用的时候,非常危险,如果你被邀请加入到使用这三者的项目中,逃之夭夭并不丢面子(起屁股走人,但是现在的似乎并不少,因为大家是在现有的稳定的软件API,进行隔离,并没有自己写bug ಥ_ಥ)
编程是控制复杂度。能够管理复杂度的工具是好工具,但是如果不是,扔掉!永远不要忘记这一点,它是UNIX智慧的重要组成部分
领取专属 10元无门槛券
私享最新 技术干货