首页 > 其他分享 >多线程/GIL全局锁

多线程/GIL全局锁

时间:2022-11-21 21:45:33浏览次数:55  
标签:__ 多线程 Thread 线程 time print 全局 GIL

目录

线程理论

进程
   进程其实是资源单位 标示开辟一块内存空间
线程
	 线程才是执行单位 表示真正的代码质量
  
注意:进程是资源分配的最小单位,线程是CPU调度的最小单位.
    每一个进程中至少有一个线程。 
  
进程可以比喻为车间  线程表示车间里面的流水线
一个进程内至少包含一个线程(主线程)

1.一个进程内可以开设多个线程
2.同一个进程下的多个线程数据是共享的 数据是可以互相更改使用的

3.进程与线程的区别
	创建进程的消耗远远大于线程, 进程越多cpu越累
  线程的运行速度远远大于进程		线程的消耗较小
  

创建线程的两种方式

from threading import Thread
from multiprocessing import Process
import time

 def task(name):
     print(f'{name} is running')
     time.sleep(2)
     print(f'{name} is over')

 if __name__ == '__main__':

     for i in range(20):
         t = Thread(target=task, args=('moon',))
         # 创建一个线程         t.start()
     print('我是主线程')
    
    

通过类创建多线程:
 
class My_Thread(Thread):
    def __init__(self,name):
        super().__init__()
        self.name = name

    def run(self):
        print(f'{self.name} is running')
        time.sleep(2)
        print(f'{self.name} is over')

t = My_Thread('moon')

t.start

线程的诸多特性

线程同进程很多方法相同
1.join 方法            # 等待线程进行结束
2.current_therad()    # 返回当前的线程变量。
3.active_count()      # 返回正在运行的线程数量
4.setDaemon(True)     # 设置守护线程
5.isAlive()           # 返回线程是否活动的

GIL全局解释器

# 官方文档对GIL的解释
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.

'''
1.在cpython解释器中存在全局解释器锁简称 GIL
  python解释器的类型:CPython,JPython Pypython(常用C解释器)
2.GIL本质其实就是一把互斥锁 用来阻止同一个进程内多个线程同时执行的
3.GIL的存在是因为CPython解释器中内存管理的线程不是安全的,由于python的垃圾回收线程
可能导致同线程并行,垃圾回收线程出现错误,线程如果同时运行,当一个数据还没有被绑定赋值,然后垃圾回收机制也同步在运行,导致可能数据被当作垃圾回收了
'''


GIL不是python的特点,而是Cpython解释器的特点
GIL是保证解释器级别的数据安全,是不同线程之间的锁
针对不同的数据还是要加不同的锁处理

验证GIL存在

from threading import Thread

num = 50

def task():
    global num
    num -= 1

t_list= []

for i in range(1,50):
    t = Thread(target=task)
    t.start()
    t_list.append(t)
for t in t_list:
    t.join()

print(num)

GIL与普通互斥锁的区别

from threading import Thread, Lock
import time

mutex = Lock()
money = 50


def task():
    global money
    mutex.acquire()
    tmp = money
    time.sleep(0.2)
    money = tmp - 1
    mutex.release()


if __name__ == '__main__':
    t_list = []
    for i in range(50):
        t = Thread(target=task)
        t.start()
        t_list.append(t)
    for t in t_list:
        t.join()
    print(money)

    
'''
首先多线程 每个线程需要去抢到GIL 有了GIL才会执行
然后 如果抢到了 GIL然后进入了IO操作 GIL就会自动释放,
所以如果不加普通的互斥锁,还是会导致所有的线程拿到的都是同一份数据

如果有了互斥锁,那就不会影响,因为每个线程都需要先抢到GIL 然后
拥有GIL锁的线程也会抢到互斥锁,当进入IO操作时,其他线程有了GIL但是
也没办法拿到互斥锁 所以这样就可以保证线程一个一个运行

'''

同一个进程下多线程是否有优势

'''
多线程是否有用要看具体情况,
IO密集型/计算密集型
'''

计算密集型: 多进程合适  可以异步操作缩短计算总耗时

IO密集型:  多线程合适  更加节省资源



计算密集型:
from  multiprocessing import Process
import os,time
from threading import Thread

def work():
    res = 0
    for i in range(1,828888):
        res +=i


if __name__ == '__main__':
    l = []
    start_time = time.time()
    for i  in range(8):
        p = Process(target=work)
        p.start()
        l.append(p)
    for p in l:
        p.join()
    print(time.time() - start_time)  # 14s


if __name__ == '__main__':
    l = []
    start_time = time.time()
    for i  in range(8):
        t = Thread(target=work)
        t.start()
        l.append(t)
    for t in l:
        t.join()
    print(time.time() - start_time) # 42s 
    
    
!!!得出结论 计算密集型 多进程比较快,多线程慢了大概3倍 !!!


IO操作密集时:

from  multiprocessing import Process
import os,time
from threading import Thread

def work():
    time.sleep(1)


if __name__ == '__main__':
    l = []
    start_time = time.time()
    for i  in range(400):
        p = Process(target=work)
        p.start()
        l.append(p)
    for p in l:
        p.join()
    print(time.time() - start_time)  # 6.6


if __name__ == '__main__':
    l = []
    start_time = time.time()
    for i  in range(8):
        t = Thread(target=work)
        t.start()
        l.append(t)
    for t in l:
        t.join()
    print(time.time() - start_time) # 1s
    
    
    
    !!!得出结论 IO密集型 多线程比较快,多线程效率太低 !!!

死锁现象

当我们自己加锁时,必须知道 抢锁后立即释放锁,因为当你在多线程多进程操作锁的时候极容易产生锁死现象,整个程序卡死
from threading import Lock, Thread
import time

mutexA = Lock()
mutexB = Lock()

class MyThread(Thread):
    def run(self):
        self.func1()
        self.func2()

    def func1(self):
        mutexA.acquire()
        print('1')
        mutexB.acquire()
        print('2')
        mutexB.release()
        print('3')
        mutexA.release()
        print('4')

    def func2(self):
        mutexB.acquire()
        print('5')
        time.sleep(2)
        mutexA.acquire()
        print('6')
        mutexB.release()
        mutexA.release()

if __name__ == '__main__':
    for i in range(10):
        t = MyThread()
        t.start()

信号量

信号量在不同的阶段可能对应不同的技术点
在并发编程中 信号量指的是锁!


在python并发编程中信号量相当于多把互斥锁(公共厕所)
	
from threading import Thread, Lock, Semaphore
import time
import random


sp = Semaphore(5)  # 一次性产生五把锁


class MyThread(Thread):
    def run(self):
        sp.acquire()
        # 同时抢5把锁
        print(self.name)
        time.sleep(random.randint(1, 3))
        sp.release()
        # 有完成就释放


for i in range(20):
    t = MyThread()
    t.start()

Event事件

一些进程/线程需要等待另外一些进程/线程运行完毕之后才能运行,类似于红绿灯,可以控制哪些进程先进行 哪些后进行

from threading import Thread, Event
import time

event = Event()  # 类似于造了一个红绿灯


def light():
    print('红灯亮着的 所有人都不能动')
    time.sleep(3)
    print('绿灯亮了 油门踩到底 给我冲!!!')
    event.set()


def car(name):
    print('%s正在等红灯' % name)
    event.wait()
    print('%s加油门 飙车了' % name)


t = Thread(target=light)
t.start()
for i in range(20):
    t = Thread(target=car, args=('熊猫PRO%s' % i,))
    t.start()
    
    
event.wait() # 等待 有了event.set()运行后才执行

标签:__,多线程,Thread,线程,time,print,全局,GIL
From: https://www.cnblogs.com/moongodnnn/p/16913465.html

相关文章