day32 并发编程之锁

并发编程之锁

1. GIL全局解释器锁

2. GIL与普通的互斥锁

3. 死锁

4. 信号量

5. event事件

6. 线程q

 

1. 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.
"""
"""
ps:python解释器有很多种  最常见的就是Cpython解释器
GIL本质也是一把互斥锁:将并发变成串行牺牲效率保证数据的安全 
用来阻止同一个进程下的多个线程的同时执行(同一个进程内多个线程无法实现并行但是可以实现并发)
    python的多线程没法利用多核优势  是不是就是没有用了?
    
GIL的存在是因为CPython解释器的内存管理不是线程安全的

垃圾回收机制
    1.引用计数
    2.标记清除
    3.分代回收


研究python的多线程是否有用需要分情况讨论
四个任务 计算密集型的  10s
单核情况下
    开线程更省资源
多核情况下
    开进程 10s
    开线程 40s

四个任务 IO密集型的  
单核情况下
    开线程更节省资源
多核情况下
    开线程更节省资源
""""""
python的多线程到底有没有用
需要看情况而定  并且肯定是有用的


多进程+多线程配合使用
"""

计算密集型

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


def work():
    res = 0
    for i in range(10000000):
        res *= i


if __name__ == '__main__':
    l = []
    print(os.cpu_count())  # 本机为8核
    start = time.time()
    for i in range(8):
        p = Process(target=work)  # 耗时  0.7752041816711426
        # p = Thread(target=work)  # 耗时 2.9953091144561768
        l.append(p)
        p.start()
    for p in l:
        p.join()
    stop = time.time()
    print('run time is %s' % (stop - start))

 

I/O密集型
# IO密集型
from multiprocessing import Process
from threading import Thread
import threading
import os,time
def work():
    time.sleep(2)


if __name__ == '__main__':
    l=[]
    print(os.cpu_count()) #本机为8核
    start=time.time()
    for i in range(4000): # 报错超过最大递归深度,这里改为400
        p=Process(target=work) #耗时2.85s多,大部分时间耗费在创建进程上
        # p=Thread(target=work) #耗时2.02s多
        l.append(p)
        p.start()
    for p in l:
        p.join()
    stop=time.time()
    print('run time is %s' %(stop-start))

 

 

2. GIL与普通的互斥锁

from threading import Thread
import time

n = 100


def task():
    global n
    tmp = n
    time.sleep(1)  # 睡1秒,所有子进程都取到了100,阻塞1秒后再减1,结果为99
    # 注销了time.sleep(1),GIL锁发挥作用,串行取值,100-100个子程序的1=0
    n = tmp - 1


t_list = []
for i in range(100):
    t = Thread(target=task)
    t.start()
    t_list.append(t)

for t in t_list:
    t.join()

print(n)  # 0

 

 

3.死锁

from threading import Thread,Lock,current_thread,RLock
import time
"""
Rlock可以被第一个抢到锁的人连续的acquire和release
每acquire一次锁身上的计数加1
每release一次锁身上的计数减1
只要锁的计数不为0 其他人都不能抢

"""
# mutexA = Lock()
# mutexB = Lock()
mutexA = mutexB = RLock()  # A B现在是同一把锁


class MyThread(Thread):
    def run(self):  # 创建线程自动触发run方法 run方法内调用func1 func2相当于也是自动触发
        self.func1()
        self.func2()

    def func1(self):
        mutexA.acquire()
        print('%s抢到了A锁'%self.name)  # self.name等价于current_thread().name
        mutexB.acquire()
        print('%s抢到了B锁'%self.name)
        mutexB.release()
        print('%s释放了B锁'%self.name)
        mutexA.release()
        print('%s释放了A锁'%self.name)

    def func2(self):
        mutexB.acquire()
        print('%s抢到了B锁'%self.name)
        time.sleep(1)
        mutexA.acquire()
        print('%s抢到了A锁' % self.name)
        mutexA.release()
        print('%s释放了A锁' % self.name)
        mutexB.release()
        print('%s释放了B锁' % self.name)

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




class Demo(object):     passobj1 = Demo()obj2 = Demo()print(id(obj1),id(obj2))
"""
只要类加括号实例化对象
无论传入的参数是否一样生成的对象肯定不一样
单例模式除外


自己千万不要轻易的处理锁的问题  

"""

 

4 信号量

# 信号量可能在不同的领域中 对应不同的知识点
"""
互斥锁:一个厕所(一个坑位)
信号量:公共厕所(多个坑位)
"""
from threading import Semaphore,Thread
import time
import random


sm = Semaphore(5)  # 造了一个含有五个的坑位的公共厕所

def task(name):
    sm.acquire()
    print('%s占了一个坑位'%name)
    time.sleep(random.randint(1,3))
    sm.release()

for i in range(40):
    t = Thread(target=task,args=(i,))
    t.start()

 

 

5 Event事件

from threading import Event,Thread
import time

# 先生成一个event对象
e = Event()


def light():
    print('红灯正亮着')
    time.sleep(3)
    e.set()  # 发信号
    print('绿灯亮了')

def car(name):
    print('%s正在等红灯'%name)
    e.wait()  # 等待信号
    print('%s加油门飙车了'%name)

t = Thread(target=light)
t.start()

for i in range(10):
    t = Thread(target=car,args=('伞兵%s'%i,))
    t.start()

 

 

6 线程q

import queue
"""
同一个进程下的多个线程本来就是数据共享 为什么还要用队列

因为队列是管道+锁  使用队列你就不需要自己手动操作锁的问题 

因为锁操作的不好极容易产生死锁现象
"""



# q = queue.Queue()
# q.put('hahha')
# print(q.get())


# q = queue.LifoQueue()
# q.put(1)
# q.put(2)
# q.put(3)
# print(q.get())


# q = queue.PriorityQueue()
# # 数字越小 优先级越高
# q.put((10,'haha'))
# q.put((100,'hehehe'))
# q.put((0,'xxxx'))
# q.put((-10,'yyyy'))
# print(q.get())

 

 

posted @ 2019-08-14 14:43  辕子  阅读(162)  评论(0编辑  收藏  举报