进程线程与GIL全局解释器锁详解
Posted zzzynx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了进程线程与GIL全局解释器锁详解相关的知识,希望对你有一定的参考价值。
进程与线程的关系:
1. 线程是最小的调度单位
2. 进程是最小的管理单元
3. 一个进程必须至少一个线程
4. 没有线程,进程也就不复存在
线程特点:
3 线程的并发是利用cpu上下文的切换(是并发,不是并行)
4 多线程执行的顺序是无序的
5 多线程共享全局变量
6 线程是继承在进程里的,没有进程就没有线程
7 GIL全局解释器锁
8 只要在进行耗时的IO操作的时候,能释放GIL,所以只要在IO密集型的代码里,用多线程就
9 很合适
线程详解:
import threading # ---》导入模块 # def func(n): # print(‘task‘,n) # t = threading.Thread(target = func,args = (1,)) # t.start() # # # for i in range(10): ---》使t的内容循坏输出10行 # t = threading.Thread(target = func,args = (‘t-%s‘%i,)) ---》target=函数名 args要求以元组形式传参,当参数只有一个时,以(参数,)的格式传参。 # t.start() ----》固定启动线程 # 多线程共享全局变量 # g=0 ---》设置一个全局变量 # def test(): # global g ----》线程共享全局变量时需要建立在声明global+全局变量上 # for i in range(10): # g +=1 # print(g) # def test1(): # global g # for i in range(10): # g +=1 # print(g) # t1=threading.Thread(target=test) ---->用线程调用test函数的结果,没有参数时,只需要输入target就行 # t2=threading.Thread(target=test1) # t1.start() # t2.start()
GIL全局解释器锁:
#GIL全局解释器锁 ---》作用是保证最多只有一个线程在使用全局变量g_num,但是不保证赋值成功 lock = threading.Lock() ----》添加互斥锁,作用是使两个线程不再并发处理,使赋值成功,注意L要大写 g_num = 0 def test1(): global g_num lock.acquire() ---》在循坏前锁上 for i in range(100000): g_num +=1 lock.release() ----》赋值结束后解放锁 def test2(): global g_num lock.acquire() for i in range(100000): g_num +=1 lock.release() t1=threading.Thread(target=test1) ---》注意T要大写 t2=threading.Thread(target=test2) t1.start() # 导致结果不对的原因(1):主线程处理py文件速度比另外两个线程赋值速度快,在没赋值结束时就又开始新一轮的赋值 t2.start() # 解决方法(1): # 在后面加上两行 t1.join() #----》即主线程等待每轮赋值结束后才重启下一轮赋值,但是这样也还是不对,只能让成功次数上升 t2.join() # 因为赋值成功率不是100%,次数越多越有可能赋值失败。 print(g_num) 解决方法(2): 添加互斥锁:lock = threading.Lock() ,保证赋值成功,缺点是速度慢
进程详解:
# 一个程序运行起来之后,代码+用到的资源称之为进程,它是操作系统分配资源的基本单位,不仅可以通过线程完成多任务,进程也是可以的 # 进程之间是相互独立的,结果互不影响也无法共享全局变量,等待上一个进程结束,下一个进程再执行。 # cpu密集的时候适合用多进程 #cpu效率高,耗资源多, import multiprocessing --》导入进程模块 import time ----》导入快捷键,将鼠标停在关键词上alt 加 enter 选择导入模块 def test1(n): time.sleep(2) ---》两秒后打印执行任务完毕,再到第二个进程 print(‘task‘,n) def test2(n): time.sleep(2) print(‘task‘,n) if __name__ == ‘__main__‘: --->相当于调用test1()和test(2),这是主进程的作用 p1 = multiprocessing.Process(target=test1,args=(1,)) --》注意P的大写 p2 = multiprocessing.Process(target=test2,args=(1,)) p1.start() ---》此进程负责调用p1进程 p2.start() ---》负责调用p2进程
进程池:
import multiprocessing import time g_num = 0 def test1(n): for i in range(n): time.sleep(1) print(‘test1‘, i) def test2(n): for i in range(n): time.sleep(1) print(‘test2‘, i) def test3(n): for i in range(n): time.sleep(1) print(‘test3‘, i) def test4(n): for i in range(n): time.sleep(1) print(‘test4‘, i) if __name__ == ‘__main__‘: #此操作必须存在,不然无法调用 pool = multiprocessing.Pool(3) #把进程声明出来括号里不写东西说明无限制,如果写数字,就是最大的进程数,即允许几个进程并发。池外的串行 pool.apply_async(test1,(5,)) #用pool去调用函数test1,参数为5格式为(5,) pool.apply_async(test2,(5,)) pool.apply_async(test3,(5,)) pool.apply_async(test4,(5,)) #以上三个进程并发处理,同时输出赋值,而4进程串行输出,因为在进程池外** pool.close() #close必须在join的前面
以上是关于进程线程与GIL全局解释器锁详解的主要内容,如果未能解决你的问题,请参考以下文章
并发编程——GIL全局解释器锁死锁现象与递归锁信号量Event事件线程queue