thread_为什么多线程是个坏主意
转 http://ifeve.com/why-threads-bad/
在 Unix编程艺术 中,提到了尽量避免多线程编程模型, 认为这样只会增加复杂度, 提倡使用多进程, 这样本质上就可以避免多线程『共享内存数据』产生的 “corruotped memory” 问题。
其中, 提到了一篇文章 Why Threads Are A Bad Idea, 对于多线程编程和事件编程分析的非常好, 具体的翻译如下:
1 介绍
线程的背景:
- 在操作系统中出现多线程
- 逐渐演变成 用户层面的编程工具
- 被认为是多种问题的一种通用解决方案
- 每一个程序员都需要成为 一个多线程编程的高手吗?
根本性的问题:
多线程的程序非常难以正确的编写!!!
替代性的方案:
使用事件驱动的编程方法
特别声明:
- 对于大部分的多线程程序,使用事件驱动是一个更好的选择
- 只有当使用CPU多核的时候, 才需要使用多线程编程
2 多线程的本质
- 一般用来管理并发问题
- 多个独立相互执行的任务
- 共享的内存
- 预先的安排机制(Pre-emptive scheduling)
- 同步机制(synchronization)
3 多线程的用途
- 操作系统: 对每一个用户进程分配一个内核线程
- 科学应用程序: 每个CPU分配一个线程(对计算要求性很高的程序)
- 分布式系统: 进程请求并行(同步记性的I/O操作)
- GUIs程序
- 线程对应用户的行为. 在长时间的后台计算过程中仍然可以处理图形展示
- 多媒体, 动画方面的程序编写
4 多线程有什么问题?
- 对于一般的程序员而言,难以掌握。
- 即使对于专家,多线程编程也是痛苦的。
5 为什么多线程编程很难?
- Synchronization(同步机制):
- 必须通过锁来共享数据
- 忘记了加锁?就会导致受污染的数据
- 死锁
- 依赖锁,会导致循环依赖
- 每个处理程序等待其他处理程序: 导致系统挂起
6 为什么多线程编程很难?
- 难以调试: 因为 数据依赖,时间依赖
- 线程破坏了抽象: 无法设计出模块化的程序
- 因为锁导致回调无法完成
7 为什么多线程编程很难?
- 很难达到非常好的性能
- 简单的锁导致了低并发
- 而精密的锁又会导致复杂度提升, 降低了一般情况下的性能
- OSes限制了性能提升(调度, 环境切换)
- 线程不受支持
- 难以支持多线程代码(mac, windows)
- 一些标志库不是线程安全的
- 内核调用, windows系统不是多线程
- 很少有多线程编程的调试工具
- 通常不需要并发场景
8 时间驱动编程
- 一个执行流进程: 没有CPU的并发
- 在时间上注册消息(通过回调)
- 事件轮询等待消息, 调用处理器模型
- 时间处理器没有抢断
- 处理器通常是 短生命周期的
9 事件驱动编程被用来干什么
- 大多数的GUIs编程:
- 一个处理器对应一个事件
- 处理器用来执行行为(撤销,删除文件等)
- 分布式系统
- 一个处理器用来对应一个输入源
- 处理进来的请求,返回结果
- 事件驱动的I/O 来处理 I/O并发
10 事件驱动编程的问题
- 长时间运行的时间处理器会导致 程序没有反应, 解决办法:
- 对于长时间运行的程序Fork off子程序处理, 当处理结束后使用事件
- 打断处理器执行(比如: 事件驱动的I/O)
- 定期回调 时间处理器中的 事件循环
- 通过处理器无法维护本地内存状态(处理器必须返回)
- 没有CPU的并发(不太合适科学计算程序)
- 事件驱动的编程并不总是被支持
11 多线程编程 VS 事件驱动编程
事件驱动编发编程尽可能的避免 并发, 而多线程编程则倾向于并发:
- 使用事件驱动编程更加容易: 不用考虑并发, 不用考虑抢占, 不用考虑同步和死锁
- 只在特定的情况下,才使用复杂的技术栈
- 使用多线程编程, 即使最简单的程序也需要面对很高的复杂度(full complexity)
使用事件驱动更加容易调试
- 事件驱动编程只和时间依赖有关, 不需要考虑内部的调度
- 问题更加容易跟踪: 较慢的按钮点击反应 和 内存数据污染 时候, 前者问题更加容易定位
12 多线程编程 VS 事件驱动编程
在单个CPU上时间驱动程序比线程更加快速
- 没有锁的覆盖
- 没有上下文环境的 切换
事件驱动编程更加面向接口编程
多线程提供了真正的并发性
- 对于多CPU的机器来说,是可以扩展性能
- 可以长时间的运行处理程序而不需要冻结
13 你需要放弃多线程吗?
不需要的情况: 对于应该程序性能要求很高的服务(比如: 数据库服务器)
但是, 尽可能的避免多线程编程:
- 对于 GUIs程序, 分布式系统, 性能要求不高的, 使用事件编程, 不是多线程
- 只有当真正的多核CPU并发需要使用到的时候,使用多线程编程
- 当使用多线程编程的时候,将多线程编程模块与其他模块进行隔离, 保持大部分代码都是单线程模型
隔离多线程的模块:
14 总结
并发从根本上是很难的, 尽可能的避免
多线程比事件更加强大,但是这种强大的功能很少真正需要
多线程编程比事件编程更加难以写出正确的代码, 只有真正的专家才能掌握
将事件 编程当做基本的开发工具(对于GUIs 和 分布式系统)
只有当性能要求很高的服务时候,才使用 多线程
thread_为什么多线程是个坏主意的更多相关文章
- C#多线程之旅(3)——线程池
v博客前言 先交代下背景,写<C#多线程之旅>这个系列文章主要是因为以下几个原因:1.多线程在C/S和B/S架构中用得是非常多的;2.而且多线程的使用是非常复杂的,如果没有用好,容易造成很 ...
- java多线程-线程通信
线程通信的目标是使线程间能够互相发送信号.另一方面,线程通信使线程能够等待其他线程的信号. 通过共享对象通信 忙等待 wait(),notify()和 notifyAll() 丢失的信号 假唤醒 多线 ...
- 用 python 实现一个多线程网页下载器
今天上来分享一下昨天实现的一个多线程网页下载器. 这是一个有着真实需求的实现,我的用途是拿它来通过 HTTP 方式向服务器提交游戏数据.把它放上来也是想大家帮忙挑刺,找找 bug,让它工作得更好. k ...
- python 多线程编程
这篇文章写的很棒http://blog.csdn.net/bravezhe/article/details/8585437 使用threading模块实现多线程编程一[综述] Python这门解释性语 ...
- python线程使用场景 多线程下载
http://blog.xiayf.cn/2015/09/11/parallelism-in-one-line http://python.jobbole.com/84327/ http://www. ...
- python多线程ctrl-c退出问题
场景: 经常会遇到下述问题:很多io busy的应用采取多线程的方式来解决,但这时候会发现python命令行不响应ctrl-c 了,而对应的java代码则没有问题: public class Test ...
- Python:使用threading模块实现多线程编程
转:http://blog.csdn.net/bravezhe/article/details/8585437 Python:使用threading模块实现多线程编程一[综述] Python这门解释性 ...
- C#中的线程(三) 使用多线程
第三部分:使用多线程 1. 单元模式和Windows Forms 单元模式线程是一个自动线程安全机制, 非常贴近于COM——Microsoft的遗留下的组件对象模型.尽管.NET最大地放弃摆脱了遗留 ...
- C#中的线程(下)-多线程
1. 单元模式和Windows Forms 单元模式线程是一个自动线程安全机制, 非常贴近于COM——Microsoft的遗留下的组件对象模型.尽管.NET最大地放弃摆脱了遗留下的模型,但很多时候它 ...
随机推荐
- 【java】java中替换中括号[ ]操作
String aa ="[1,2,3]"; aa = aa.replaceAll("[\\[\\]]",""); 结果为 1,2,3
- 如何使用Less?
LESS是动态样式语言,赋予CSS动态语言的特性,如变量.继承.运算.函数,使得CSS更方便编写与维护.>>官网 less @color:#ff0000; body{color:@colo ...
- PVS-Studio静态通用分析规则
通用分析 PVS - Studio产品包含了一套通用静态分析规则,用于检测在C / C ++/ C+11应用程序中大范围内的各种缺陷. 通用的规则集帮助您发现逻辑错误,拼写错误,导致访问冲突的代码片段 ...
- 离线安装ocp3.11需要注意的事情
检查阶段 运行部署前检查的时候 # ansible-playbook -vv playbooks/prerequisites.yml 需要看看play recap是否全过,如果不过需要定位原因,反复执 ...
- Java9 modules (Jigsaw)模块化迁移
要点 通过模块化的方式开发应用程序,实现更好的设计,如关注点分离和封装性. 通过Java平台模块化系统(JPMS),开发者可以定义他们的应用程序模块,决定其他模块如何调用他们的模块,以及他们的模块如何 ...
- 移动APP安全在渗透测试中的应用
安全爱好者研究的往往是app的本地安全,比如远控.应用破解.信息窃取等等,大多人还没有关注到app服务端的安全问题,于是在这块的安全漏洞非常多. 移动app大多通过web api服务的方式跟服务端交互 ...
- 30分钟Git命令“从入门到放弃”
git 现在的火爆程度非同一般,它被广泛地用在大型开源项目中,但是初学者非常容易“从入门到放弃”,各种命令各种参数,天哪,宝宝要吓哭了.实际上新手并不需要了解所有命令的用途,学习是需要一个循序渐进的过 ...
- dubbo forbid 注意的几种方式
1.检查所调用的项目模块是否起来了 2.如果起来后,检查该模块配置是否正确 3.服务端起来后与管理端的项目内容不一致(比如服务端增加了东西,管理端没有更新)
- 利用SmtpClient发送邮件
1 163邮箱 HOST:smtp.163.com public static string CreateTimeoutTestMessage(string server) { string Suc ...
- Junit核心——测试类(TestCase)、测试集(TestSuite)、测试运行器(TestRunner)
首先,把这三个定义简单的说明一下: 1.测试类(TestCase):一个包含一个或是多个测试的类,在Junit中就是指的是包含那些带有@Test注解的方法的类,同一样也被称作“测试用例”; 2.测试集 ...