首先须要明确的一点是GIL并非Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。html
就比如C++是一套语言(语法)标准,可是能够用不一样的编译器来编译成可执行代码。python
>有名的编译器例如GCC,INTEL C++,Visual C++等。Python也同样,一样一段代码能够经过CPython,PyPy,Psyco等不一样的Python执行环境来执行。linux
像其中的JPython就没有GIL。然而由于CPython是大部分环境下默认的Python执行环境。因此在不少人的概念里CPython就是Python,也就想固然的把GIL归结为Python语言的缺陷。因此这里要先明确一点:GIL并非Python的特性,Python彻底能够不依赖于GILwindows
只有CPython 有GIL全局解释器锁安全
GIL本质就是一把互斥锁,既然是互斥锁,全部互斥锁的本质都同样,都是将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。多线程
能够确定的一点是:保护不一样的数据的安全,就应该加不一样的锁。并发
执行python程序默认会生成一个进程 这个进程就是这个python解释器程序函数
#! /usr/bin/env python # -*- coding: utf-8 -*- import time import os print os.getpid() time.sleep(1000)
[root@salt-server-192 ~]# python create_process.py 1343
#在windows下查看 tasklist |findstr python #在linux下下查看 ps -aux |grep python
在一个python的进程内,不只有这个程序的的主线程或者由该主线程开启的其余线程,还有解释器开启的垃圾回收等解释器级别的线程,总之,全部线程都运行在这一个进程内ui
一、全部数据都是共享的,这其中,代码做为一种数据也是被全部线程共享的(test.py的全部代码以及Cpython解释器的全部代码)
例如:test.py定义一个函数work,在进程内全部线程都能访问到work的代码,因而咱们能够开启三个线程而后target都指向该代码,能访问到意味着就是能够执行。spa
二、全部线程的任务,都须要将任务的代码当作参数传给解释器的代码去执行,即全部的线程要想运行本身的任务,首先须要解决的是可以访问到解释器的代码。
接上:
若是多个线程的target=work,那么执行流程是
多个线程先访问到解释器的代码,即拿到执行权限,而后将target的代码交给解释器的代码去执行
1.每起一个进程,在内存空间都会默认生成一个主线程
线程的代码 taget参数 指向python代码 。而后把python代码,当作参数传给解释器的代码去执行,即全部的线程要想运行本身的任务,首先须要解决的是可以访问到解释器的代码。
图片上的参数就是python代码
2.进程内能够开好多个线程
CPython里面有一个垃圾回收机制 也是执行解释器代码,因此在进程内,内存空间会有一个垃圾回收线程
垃圾回收线程运行的是python解释器代码
由于进程内有4个线程,垃圾回收线程和其余线程会同时执行,垃圾回收线程有可能和其余线程工做冲突,致使数据不安全,
因此要控制 这些线程一个个运行 须要在CPython解释器里加锁
加了互斥锁每一个线程要运行,每一个线程抢着加锁, 一次执行 只能加锁require() 一次 再加锁require() 一次就变成阻塞状态 要等到释放release() 以后 再加锁require(),
同一时间只能有一个线程抢到锁,其余线程都要等待
1.GIL全局解释器锁本质就是互斥锁,加了GIL全局解释器锁 同时运行的多个线程,变成一个一个运行 ,效率低了, 但保证数据安全
2.只有Cpython解释器才有GIL ,有了互斥锁,对CPython 解释器来讲 每启动一个进程 这个进程内的多个线程 同一时间只能有一个在运行
CPython的垃圾回收机制 定时销毁 定时启动的