侧边栏壁纸
       百度一下
  •  云烟 4天前 在线
  •  累计撰写 60 篇文章
  •  累计收到 30 条评论
python从异步到多线程“陷阱”
2023年03月02日 175阅读 0评论 5点赞
多线程【一般】来说是可以提升效率的,但有额外情况,同时,初学者在使用多线程时往往会忽视一些问题,于是有了本文

本文知识点大致如下,由浅入深:
[灯泡]同步与异步
[灯泡]进程与线程
[灯泡]阻塞与非阻塞
[灯泡]线程安全
[灯泡]守护程序(daemon)
[灯泡]全局解释器锁(GIL)
[灯泡]多线程何时【无意义】

[彩虹]下文有序号的为理论知识,要是嫌烦也可以直接看代码,部分图片代码传不下了,评论区再发

——————那么开始正文

❶同步与异步
这应该是最简单的概念了,一笔带过

同步就是按顺序执行,即一段代码从上到下一行行执行,而异步则相反,它指的是多段代码同时执行

❷进程与线程
计算机的两大核心分别为运算器和存储器,它们决定了一个设备的【硬件瓶颈】,每个任务都是一个进程,例如你打开电脑后,同时运行多个软件,也就创建了多个进程,进程可以再细分为线程

简单来说【一个程序至少有一个进程,一个进程至少有一个线程】

这里顺便科普下cpu的知识,即便是【单核】cpu,也能实现【多线程】,因为cup在工作的时候,总是会不断切换进程和线程执行,只不过的这个切换的时间很短(可以达到【微秒】的程度),以至于察觉不出来

可能前几微秒在执行浏览器的进程,后几微秒又跑到另一个程序去了,如此循环往复,直到关机

这块知识不用操心,因为cpu何时切换进程线程是由【操作系统】决定的,我们了解即可

❸阻塞与非阻塞
这个也是简单的概念,阻塞就是当前任务会“卡住”,只有当前执行完毕程序才能继续运行下一个任务,非阻塞则相反

好了,上面的都是理论知识,接下来可以看看代码了【图一】是在py中创建多线程,结果为【图二】

❹线程安全
在py中,每个线程操作的变量是【共享】的,也就是说,可能存在多个线程操作【同一个】变量,导致结果【覆盖】的问题,即线程不安全

参考代码见【图三】【图四】

比较常见解决方案是使用【线程锁】

如【图五】【图六】

❺守护程序daemon
在py中,每个线程默认为【非】daemon,只有【所有】的非daemon结束了,程序才会结束

当然,你也可以手动指定一个子线程位daemon,只需要在实例化时传入Thread(daemon=True)即可,这里省略了其他参数,避免混淆,实际编程时应该补全(参考图片代码)

❻全局解释器锁GIL
这个是解释器尝尝被人【诟病】的一种机制,在CPython这类解释器中,线程想要获取执行权限,必须要拿到GIL锁

⭐这在很大程度上导致了py的多线程在cpu密集型任务中并【不能】同时使用多个cpu,导致py多线程效率大打折扣,甚至在某些情况下【相当】于单线程

⭐这也是《python参考手册》和《python cookbook》的作者David Beazley说“py线程毫无用处”的原因

但GIL并非一无是处,它简单粗暴的解决了线程安全问题,以至于部分语言解释器依旧选择使用(如Ruby)

❼多线程何时无意义
计算机任务可以简单分为【IO】密集型和【CPU】密集型

根据❻给出的定义,在使用部分py解释器时,由于GIL机制,cpu密集型多线程效率低下,但好在IO密集型(例如爬虫)一般不受影响

代码参考【图七】

[彩虹]py的异步还有很多知识点是本文没涉及到的,我就权当抛砖引玉了,当然,后期如果有空还会补充,过年期间来兴致了说不定能多写几篇,就酱~

[彩虹]pluie
[彩虹]2023-01-28
5

—— 评论区 ——

昵称
邮箱
网址
取消