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

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

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等待线程的话结果以下线程

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

此例子为守护线程的例子,如图所示,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密集性,多线程仍是有显著的提高的。

相关文章
相关标签/搜索