并发编程/GIL
Posted Mitsuis
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发编程/GIL相关的知识,希望对你有一定的参考价值。
进程:
进程就是一个程序在一个数据集上的一次动态执行过程。进程一般由程序、数据集、进程控制块三部分组成。我们编写的程序用来描述进程要完成哪些功能以及如何完成;数据集则是程序在执行过程中用它来控制和管理进程,它是系统感知进程存在的唯一标识。
为了实现多道技术,使CPU使用率更高,系统会经常进行进行间的切换,切换会发生在出现IO操作的时候,以及系统固定时间的切换。
线程:
线程的出现是为了降低上下文切换的消耗,提高系统的并发性,并突破一个进程只能干一样事的缺陷,使到进程内并发成为可能。线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合和堆栈共同组成。线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能。线程没有自己的系统资源。
进程与线程的关系:
1.一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
2.资源分配给进程,同一进程的所有线程共享进程的所有资源。
3.CPU分给线程,即真正在CPU上进行的是线程。
Pyhon的多线程:由于GIL导致同一时刻同一进程只能有一个线程。
并行和并发:
并行处理(Parallel Processing)是计算机系统中能同时执行两个或更多个处理的一种计算方法。并行处理可同时工作于同一程序的不同方面。并行处理的主要目的是节省大型和复杂问题的解决时间。并发处理(concurrency Processing):指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机(CPU)上运行,但任一个时刻点上只有一个程序在处理机(CPU)上运行
并发的关键是你有处理多个任务的能力,不一定要同时。并行的关键是你有同时处理多个任务的能力。所以说,并行是并发的子集
threading模块
线程对象的创建:
thread直接创建:
1 1 import time 2 2 import threading 3 3 def tingge(): 4 4 print(‘听歌‘) 5 5 time.sleep(3) 6 6 print(‘听歌结束‘) 7 7 8 8 def xieboke(): 9 9 print(‘写博客‘) 10 10 time.sleep(5) 11 11 print(‘写博客结束‘) 12 12 13 13 t1 = threading.Thread(target = tingge) #生成线程实例,target=函数名,args = 函数需要传参的参数,默认可以不传 14 14 t2 = threading.Thread(target = xieboke) 15 15 16 16 t1.start() #启动进程 17 17 t2.start() 18 18 print("ending!") 19 20 21 #继承Thread式自定义创建: 22 import threading 23 import time 24 class MyThread(threading.Thread): 25 26 def __init__(self,num): 27 threading.Threa.__init__(self) 28 self.num = num 29 def run(self): 30 print("running on number:%s" % self.num ) 31 time.sleep(3) 32 33 t1 = MyThread(56) 34 t2 = MyThread(78) 35 36 t1.start() 37 t2.start() 38 print(‘ending‘)
以上第一段代码就实现了一个并发的效果。tingge与xieboke函数(子线程)跟主逻辑“print(‘ending!‘)”(主线程)同时启动,先几乎同时执行【print(‘听歌‘)、print(‘写博客‘)、print("ending!")】随后IO操作“sleep”,等3S听歌结束,再等2S写博客结束。如果使用串行的方法,程序全部执行则一共需要差不多8S的时间,降低了CPU的使用效率。
Threading的方法:
join:在子线程完成运行之前,这个子线程的父线程将一直被阻塞。
setDaemon:
‘‘‘ 将线程声明为守护线程,必须在start() 方法调用之前设置,如果不设置为守护线程程序会被无限挂起。 当我们在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程 就分兵两路,分别运行,那么当主线程完成 想退出时,会检验子线程是否完成。如果子线程未完成,则主线程会等待子线程完成后再退出。但是有时候我们需要的是只要主线程 完成了,不管子线程是否完成,都要和主线程一起退出,这时就可以 用setDaemon方法啦‘‘‘
这么看来,是不是当要执行多个线程,是不是都可以用Threading来解决呢?
其实并不是,对于计算密集型任务,Python的多线程并没有用。由于GIL的存在在,一个线程拥有了解释器的访问权之后,其他的所有线程都必须等待它释放解释器的访问权,即使这些线程的下一条指令并不会互相影响。
因此Python并不能达到一个并发的效果,同一时间只能运行一个线程,所以对于计算密集型任务,多个线程同时启动,CPU就需要频繁的来回切换,这样就加入了大量的切换时间。而串行的方式则只需要切换少数的几次,
因此对于计算密集型任务,Python的多线程并没有用,而对于上面的IO密集型任务,Python的多线程是有意义的。
那么Python有没有使用多核的方法呢? 答案是可以的,但只能是开多个进程来实现,那样弊端也显而易见,会增大资源开销而且进程间相互的切换也会非常复杂。
解决的着重点:协程+多进程/ IO多路复用
以上是关于并发编程/GIL的主要内容,如果未能解决你的问题,请参考以下文章