35、python并发编程之多线程(理论篇)

嗯...说说这多线程吧...
一、啥是线程 线程啊,就像流水线上的一个工作单元。
一个进程(车间)里头,可以有好几个线程一起干活,但他们用同一个地址空间(共享资源)。
北京地铁1 3 号线是个线程,但所有线都共用北京地铁这个资源池。

核心就俩点:
进程是攒资源的,线程是CPU跑的。

二、为啥线程开销小 造一个进程,得申请新空间、建新流水线,挺费劲的。
但造线程?直接在老进程里加条线,不用申新空间,快多了。

关系上:
进程之间是抢资源的(比如迅雷抢网速)。

线程之间是帮忙的(迅雷里头各个线程协同干活)。

三、线程和进程到底啥区别 1 . 地址空间
线程共享进程的地址空间。

进程有自己独立的地址空间。

2 . 数据访问
线程直接用进程的数据。

进程得先抄一份父进程的数据才能用。

3 . 通信
线程之间直接说活。

进程得用IPC(进程间通信)这玩意儿。

4 . 创建和控制
新线程造得快。

新进程得抄父进程,慢。

线程能管同进程其他线程。

进程只能管自己造的子进程。

5 . 主线程影响
主线程变天了(比如取消、改优先级),同进程其他线程都得受影响。

父进程变天了,子进程照样跑。

四、为啥要用多线程 场景:多个任务得用同一块数据的时候,就得在一个进程里开多个线程。

好处: 1 . 共享地址空间:不用来回传数据。
2 . 轻量级:造线程比造进程快1 0-1 00倍。
3 . 重叠运行:计算和I/O同时干,能提速。
4 . 多核利用:多核CPU上能跑得开(但Python有GIL这坑)。

五、多线程例子 字处理软件:你打字、处理文字、自动存盘,这三个任务得操作同一份数据。
要是单线程,得等一个干完才能干下一个。
多线程就能同时干。

六、经典线程模型
共享资源:多个线程用同一个地址空间,叫轻量级进程。

运行方式:CPU在多个线程间飞快切换,跟多进程似的。

协作关系:同进程的线程能互相看内存。

堆栈:每个线程有自己那仨。

线程切换:thread库不能强制线程让CPU,得自己调thread_yield主动放弃。

问题:
子线程继承:父进程卡住了,子进程跟着卡?
资源竞争:一个线程关文件,另一个写文件就炸了。

七、POSIX线程(了解即可) IEEE搞了个标准叫Pthread,大部分UNIX系统都支持。

八、用户空间线程(了解即可)
用户级线程:切换由程序自己控制,不用内核帮忙,省事但多核用不了(比如Linux pthread)。

运行时系统:每个进程有自己调度线程,同一时间只能干一个。

九、内核空间线程(了解即可)
内核级线程:切换由内核控制,但进出内核态费劲。
能多核跑(Windows线程)。

十、用户级和内核级对比(了解即可)
内核线程:OS知道它,创建撤销靠内核,干系统调用整个进程中断。
CPU调度按线程。

用户线程:OS不知道它,调度简单,不支持线程的系统也能用,但多核只能分时。

十一、混合实现(了解即可) 用户级+内核级结合,内核调度内核线程,每个内核线程对应多个用户线程。

十二、线程小故事 线程就是进程里的协作单位,像地铁线共享地铁资源。

推荐学习资源 Egon推荐全套视频,适合零基础自学,或者在职工程师升级。

java编程之多线程实战指南(设计模式篇),从基础到避坑。

说实话,聊Java多线程这事儿,我当年也是边啃书边踩坑过来的。
进程和线程这概念,说起来简单,但真遇到问题才明白区别有多大。
我有个同事当年就是,写个简单的后台任务,结果CPU飙到1 00%,后来一查,线程开了几十个没关,直接把服务器拖垮了——这就是典型的线程泄漏。

说到实现方式,继承Thread确实方便,但Java那单继承限制太头疼了。
我之前有个项目用这个,结果想同时继承另一个工具类直接崩了。
后来改用Runnable,感觉思路开阔多了。
记得那个重构的下午,咖啡喝了两杯,代码写完一测,嘿,居然跑得顺多了。
这让我明白,设计模式不是纸上谈兵,真用起来,灵活度直接体现在细节里。

保护性暂挂模式(GuardedSuspension)我印象特别深。
有次做消息队列,生产者塞得快消费者取得慢,队列空了生产者就一直卡在那儿,取慢了消费者也干等着。
用wait/notify一调,问题立解决。
不过这玩意儿用不好,线程醒过来发现条件还是不满足,可能比一直跑还耗电。
记得有回我忘了加while循环,结果系统莫名其妙变慢了,调试了半天才发现——真是细节决定成败。

两阶段终止模式(Two-PhaseTermination)我也踩过坑。
有个定时任务,想优雅停用,结果忘了加volatile修饰符。
后来重启服务器发现那线程还挂着,CPU用了一半跑不动别的。
这教训太深刻了,说真的,写代码时总得想想最极端的情况,比如用户突然杀进程、服务器突然断电这种。
我当时也没想明白为啥不加volatile就出问题,后来查资料才知道,这跟JVM的指令重排有关,太玄乎了。

线程池(ThreadPool)绝对是救星。
我之前写一个处理大量小任务的系统,没用线程池直接开线程,结果服务器内存直接爆掉。
改用FixedThreadPool一弄,性能直接翻倍。
不过这玩意儿也有坑,比如拒绝策略没设置好,任务堆积起来比啥都闹心。
记得有次系统压力太大,任务队列爆了,后台日志直接刷屏,那场面...算了,不提也罢。

说到共享数据同步,我真是吃过大亏。
有回写个计数器,多个线程同时增,结果取出来的数不对。
各种试,最后发现用synchronized锁住方法就行。
但后来学Atomic类,发现性能更好,这又让我想起,技术选型不能只看简单,得看场景。
比如在高并发下,synchronized可能让CPU干等着,而Atomic类直接用硬件级别的CAS操作,效率高多了。

死锁我碰到过一次,两个线程互相抢锁,结果系统卡死。
那真是够呛,最后只能重启。
不过这次之后我养成了习惯,锁的获取顺序固定写死,或者用tryLock加超时,死锁基本没再犯过。

监控线程状态也挺重要。
我有个项目用JConsole,每次出问题都能直接看到线程堆栈,省了多少事儿。
不过说实话,JConsole用着有点老,现在新系统多用VisualVM,界面好看多了。

说到底,多线程这东西,基础得扎实,设计得巧妙,执行得严谨。
我当年写第一个多线程程序时,以为随便开几个线程就能跑飞系统,结果发现真是得按规矩来。
现在回想起来,那些踩过的坑,都是最宝贵的经验。

编程中线程是什么意思图解

比如昨天晚上,我在用电脑写东西,旁边另一个窗口在后台下载文件,感觉电脑有点卡。
我关掉下载,我的写东西速度立马快了。
这就是线程和进程的事儿。

线程就像是电脑里同时在做几件事的小帮手,写东西是主要任务,下载是次要任务。
写东西那个帮手,它可以直接用电脑的内存和资源,不用像下载那个帮手那样每次都要去别的房间找东西,所以写东西就快多了。

我在写代码的时候,有时候会用多线程,比如在一个程序里同时检查拼写和保存进度。
检查拼写那个线程,它随时可以停下来,让保存进度的线程先跑一会儿,等保存好了,拼写那个又接着干,这样效率高。
要是用进程,每个检查和保存都得单独开个房间,来回跑着找东西,就慢了。

Java里用线程挺简单的,我写个类,然后加上run方法,再new一个对象,点start,线程就转起来了。
就像我昨天写东西,我只要开始写,它就自己转起来了,不用我管。
但是要注意,有时候写东西的时候,我可能要保存,这时候我得让写东西那个线程停一停,不然保存的时候它还在改东西,就出错了。

等等,还有个事,有时候写代码的时候,线程之间会互相看对方的数据,这时候就得小心,别一个在看,一个在改,那就乱套了。
比如我昨天写东西的时候,保存进度那个线程在改文件,写东西那个线程还在用旧的数据,结果保存完了东西乱掉了。
这就像两个人同时在看同一个本子,一个人在写,一个人在念,结果念的跟写的对不上号。
所以有时候得加个锁,让一个人用完了再让另一个人用,就像我写东西的时候,先保存,保存完了再接着写,这样就不会出错了。