Python 多线程无用?深入总结 二(深入了解GIL 线程守护 线程进程CPU关系)

知识都是由浅入深的过程,之前看的书比较浅,知识表面上使用下多线程,对多线程编程的一些细节说的略浅。在后来的学习中,发现了遗漏了一些details的问题特此补上

1.threading.Tread()直接创建线程实例与threading.start_new_thread()的区别是什么?

答:

最大的区别就是,如果直接new新的线程,那么程序运行到了new_thread会直接开始运行线程。但是实例化thread会在实例化结束后,有start命令后才开始运行线程,所以我们使用了threading.Thread()。

2.join(timeout=)与setDaemon

join(timeout=),这个方法为threading module比thread module多的方法,也是推荐使用threading的原因:由于threading module中有线程守护机制,运行 thread1.join()

那么thread1线程会被守护,其意思就是等待thread1执行完或者在timeout参数规定的等待时间内,thread1一直在执行的。但是如果在thread module里面如果想完成这样的功能,就需要引入锁的概念(分配、获取、释放、检查锁状态等),很明显就太麻烦了。

对于join()方法而言,其另外一个重要方面是其实他根本不需要调用。一旦线程启动,他们就会一直执行,知道给定的函数完成后退出。如果主线程还有其他事情去做,而不是等待这些线程完成(例如处理新的用户请求),就可以不调用join().join方法只有在你需要等待线程完成的时候才是有用的。

思辨

我们在使用Python时候说的主线程,可以理解为python程序,即主线程,python程序coding中启动的线程可以视为子线程。

主进程的子进程或者线程,如果被set为守护线程或者进程那么,等待主进程或者线程执行完毕后,其子线程或者进程就直接被销毁,不会等到其执行完毕后再结束主进程。

图例中并没有设置守护线程或者等待线程。 但是如果我在子线程后加了join等待线程的话结果如下

此时果然主线程等待子线程执行结束后再开始执行(可理解为悬停)

此例子为守护线程的例子,如图所示,start前面设置了子线程为守护线程那么,主线程结束,子线程也被迫结束。

注:

主线程在其他非守护线程结束后,才算真正结束。因为主线程结束,意味着进程结束,所以操作系统给进程分配的资源都要被收回,所以必须确保非守护线程运行完毕。

3 GIL:

首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。 就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码。有名的编译器例如GCC,INTEL C++,Visual C++等。Python也一样,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行。像其中的JPython就没有GIL。然而因为CPython是大部分环境下默认的Python执行环境。所以在很多人的概念里CPython就是Python,也就想当然的把GIL归结为Python语言的缺陷。所以这里要先明确一点:GIL并不是Python的特性,Python完全可以不依赖于GIL.

介绍:

GIL本质上就是一把互斥锁,既然是互斥锁那么都是将并行变为串行,从而保证同一时间内数据只能被一个任务修改,进而保证数据安全。每次执行python程序的时候,都会产生一个独立的进程。例如python a.py b.py c.py,这样就启动了三个不同的python。

那么对于一个进程中,含有主线程,还含有其他因为主线程开启的线程,还有解释器开启的垃圾回收等解释器级别的线程,总之,所有线程都运行在这个进程内。

实验

在一个python脚本中定义一个函数work,启动三个线程访问它(target=work),如果可以调用,我们就可以理解为线程访问成功。,这个coding是线程池中共享的。

多个线程target=work,那么执行流程就是每一个线程拿到执行权限,然后交到解释器中去解释。 那么这就导致了一个问题,同一行数据100,那么线程执行x=100的时候,垃圾回收线程要收回x=100,如下加GIL锁,保证python解释器同一时间执行一个任务代码。

4 Python 多线程到底有用吗?

先思考三个问题:

1.CPU是用来干嘛的(计算还是I/O)?

2.多cpu,意味着可以有多个核并行完成计算,所以多核提升的是计算性能。

  1. 每个cpu一旦遇到I/O阻塞,仍然需要等待,所以多核对I/O操作没什么用处 。

举一个例子,计算相当于吃饭,CPU相当于一个人,那么我们一个人吃饭快,还是多个人吃饭快?当然是多个人,所以多个CPU是性能提升。I/O阻塞相当于,上菜阻塞,那么如果是I/O密集型的饭局,一只不上菜,叫一票人也没用。反过来讲如果上菜充足,那当然是人越多越好。

所以对于计算来说CPU越多越好,但是对于I/O来说,再多CPU也没用,当然对于一个python程序来说CPU多,肯定执行效率会有所提高。因为一个py程序并不是纯计算或者是I/O密集的程序,所以只能去看程序是I/O密集型的还是计算密集的。

案例:如果我们有四个任务需要处理,那么:

解决方案

1.四个进程

2.一个进程:下四个线程

单核情况下:

1.如果四个任务是计算密集型,没有多核来并行计算,方案一徒增了创建进程的开销,方案二胜 2.如果四个任务是I/O密集型,方案一创建进程的开销大,且进程的切换速度远不如线程,方案二胜

多核情况下:

1.如果四个任务是计算密集型,多核意味着并行计算,在python中一个进程中同一时刻只有一个线程执行用不上多核,方案一胜 2.如果四个任务是I/O密集型,再多的核也解决不了I/O问题,方案二胜

结论

现在电脑都是多核的,对于计算密集型的多线程并没有多大的提升性能,但是如果是I/O密集性,多线程还是有显著的提升的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值