并发编程简介
并发简史
早期的计算机没有操作系统,它们从头到尾只能单独执行一个程序,该程序独占所有资源,由于当时计算机资源比较稀缺和昂贵,所以存在着大量的资源浪费。操作系统的出现改变了这一现状,它让各个程序在独立的进程中运行,为各个独立运行的进程分配各种资源。
之所以提供操作系统来实现多个程序同时执行,主要基于以下原因(促使进程出现的原因):
- 资源利用率:当有任务因为外部输入输出等操作阻塞执行时,可以在等待的同时运行其他任务,提高了资源的利用率
- 公平性:不同用户和程序对计算机有着相同的使用权(按时间片划分,而不是一个程序从头执行到尾)
- 便利性:计算多个任务时,应该编写多个程序,每个程序要执行时进行必要的通信,这边编写一个程序执行所有任务要容易实现
串行编程的优势在于其直观性和简单性,因为它模仿了人类的工作方式:每次只做一件事情,做完了再做另一件。 例如,首先起床、穿睡衣、然后下楼、喝早茶。在编程世界中这些动作必须进一步细化。例如喝早茶可以细化为:打开橱柜,挑选茶叶,将茶叶放入杯中,看茶壶中是否有足够的水,如果没有,则将水注入茶壶,放在火炉上,点燃火炉,然后等水烧开。因为最后一步具有一定程度的异步性,所以你一般不会干等,可以利用这个时间去洗脸刷牙,只要水壶响后,回来泡茶就可以了。
上述促使进程出现的原因同样了促使了线程的出现。
线程的优势
- 发挥多处理器的强大能力:当前多核处理器盛行,多线程能够充分利用多核优势,提高处理器利用率
- 建模的简单性:使用线程可以将复杂且异步的工作流进一步分解为一组简单并且同步的工作流,每个工作流在一个单独的线程中运行,并在特定的同步位置进行交互
- 异步事件的简化处理
- 响应更灵敏的用户界面
线程带来的风险
- 安全性问题:没有足够同步的情况下,多个线程的执行顺序不可预测。竞态条件、指令重排序;关注“永远不发生糟糕的事情”
- 活跃性问题:当某个操作无法执行下去,就会发生活跃性问题,如死锁;关注“某件正确的事情最终会发生”
- 性能问题:注意上下文切换开销,同步机制抑制某些编译器优化
线程无处不在
即使程序中没有显示创建线程,但框架中仍可能创建了线程,因此书写代码时需要仔细考虑