zoukankan      html  css  js  c++  java
  • 线程的进一步探究

    在cpython(c语言的解释器)中,同一个进程下开启多线程,同一时刻只能有一个线程执行,没有办法利用多和优势
    GIL是针对cpython解释器的。
    GIL就是一把互斥锁(牺牲了效率但是保证了数据的安全性)
    GIL全局解释器存在的原因是应为cpython解释器的内存管理不是线程安全的。
    Cpython解释器上有一把GIL全局解释器锁。
    同一个进程下的多个线程不能实现并行,但是能够实现并发,多个进程下的线程能够实现并行。
    GIL内部有垃圾回收机制

    python的垃圾回收机制:1,引用计数 2,标记清楚 3,分代回收

    也就是说在同一进程下多个线程是不可能实现并行的但是可以实现并发,相反,多个进程下的线程可以实现并行。

    多个线程或进程下的不同情况:

    1、基于计算密集型

      在单核情况下:基于计算的使用多线程比较好,因为在相同的进程数下,多线程消耗的资源少

      在多核情况下:开四个进程可能需要10s左右运算结束,而开四个线程需要40S左右

    2、基于io密集型

      在单核情况下:多线程相对好一点

      在多个情况下:多线程相比好一点

    1、基于计算密集型:

    from multiprocessing import Process
    from threading import Thread
    import os,time
    def work():
        res = 0
        for i in range(1000000):
            res*=i
    if __name__ == '__main__':
        l=[]
        print(os.cpu_count()) #获取机器核心数
        start = time.time()
        for i in range(8):
            p = Process(target=work)    #进程    # 0.5842239856719971
            # p = Thread(target=work)     #线程   # 0.00799560546875
            l.append(p)
            p.start()
        for p in l:
            p.join()
        stop = time.time()
        print('run time is %s' %(stop-start))

    2、基于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()) # 本机核心数
        start=time.time()   # 当前时间
        for i in range(400):    # 400个并发
            # p = Process(target=work)    #进程 28.971384525299072
            p = Thread(target=work)     #线程 2.0688133239746094
            l.append(p)
            p.start()
        for p in l:
            p.join()
        stop = time.time()
        print('run time is %s' % (stop -start))

    二、GIL与自定义互斥锁

      GIL解释器锁是针对线程加锁;互斥锁是针对数据的

    from threading import Thread,Lock
    import time
    
    mutex = Lock()
    n = 100
    def task():
        global n
        mutex.acquire() #加锁
        tmp = n
        time.sleep(0.1)
        n = tmp -1
        mutex.release() #解锁
    t_list =[]
    for i in range(100): #开启100个线程
        t = Thread(target=task)
        t.start()
        t_list.append(t)
    for t in t_list:
        t.join()
    print(n)    #输出 0 
    “”“
    对于不同的数据,想要保证安全,需要加不同的锁处理
    GIL并不能保证数据的安全,它是多Cpython解释器加锁,针对的是线程
    保证的是同一个进程下多个线程的安全
    ”“”

    死锁和递归锁

    递归锁:

    # 死锁和递归
    from threading import Thread,Lock,RLock
    import time
    
    '''
    自定义锁一次acquire必须对应一次release,不能连续acquire
    递归锁可以连续acquire,每次acquire一次计数加一:针对的是第一次抢到我的人
    '''
    
    
    mutexA = mutexB = RLock()  # 抢锁后会有一个计数,抢一次计数加一,针对的是第一个抢到我的人
    class Mythead(Thread):
        def run(self):
            self.func1()
            self.func2()
        def func1(self):
            mutexA.acquire()
            print('%s 抢到A-1锁了' % self.name)
            mutexB.acquire()
            print('%s 抢到B-2锁了' % self.name)
            mutexB.release()
            print('%s 释放了B-1-1锁' % self.name)
            mutexA.release()
            print('%s 释放了A-2-1锁' % self.name)
    
    
        def func2(self):
            mutexB.acquire()
            print('%s 抢到B-3-1锁了' % self.name)
            time.sleep(1)
            mutexA.acquire()
            print('%s 抢到A-4-1锁了' % self.name)
            mutexA.release()
            print('%s 释放了A-4-2锁' % self.name)
            mutexB.release()
            print('%s 释放了B-3-2锁' % self.name)
    
    if __name__ == '__main__':
        for i in range(100):
            t = Mythead()
            t.start()

    死锁:

    from threading import Thread,Lock,RLock
    import time
    
    '''
    自定义锁一次acquire必须对应一次release,不能连续acquire
    递归锁可以连续acquire,每次acquire一次计数加一:针对的是第一次抢到我的人
    '''
    mutexA = Lock()
    mutexB = Lock()
    
    # mutexA = mutexB = RLock()  # 抢锁后会有一个计数,抢一次计数加一,针对的是第一个抢到我的人
    class Mythead(Thread):
        def run(self):
            self.func1()
            self.func2()
        def func1(self):
            mutexA.acquire()
            print('%s 抢到A-1锁了' % self.name)
            mutexB.acquire()
            print('%s 抢到B-2锁了' % self.name)
            mutexB.release()
            print('%s 释放了B-1-1锁' % self.name)
            mutexA.release()
            print('%s 释放了A-2-1锁' % self.name)
    
    
        def func2(self):
            mutexB.acquire()
            print('%s 抢到B-3-1锁了' % self.name)
            time.sleep(1)
            mutexA.acquire()
            print('%s 抢到A-4-1锁了' % self.name)
            mutexA.release()
            print('%s 释放了A-4-2锁' % self.name)
            mutexB.release()
            print('%s 释放了B-3-2锁' % self.name)
    
    if __name__ == '__main__':
        for i in range(100):
            t = Mythead()
            t.start()

    线程Queue

    普通queue先进先出
    import queue
    # 普通,先进先出queue
    q = queue.Queue(3)
    q.put(1)
    q.put(2)
    q.put(3)
    print(q.get())
    print(q.get())
    print(q.get())
    '''
    输出:
    1
    2
    3
    '''
    # 先进后出
    import queue
    q=queue.LifoQueue(3)
    q.put(1)
    q.put(2)
    q.put(3)
    print(q.get())
    print(q.get())
    print(q.get())
    '''
    3
    2
    1
    '''
    # 优先级
    import queue
    q = queue.PriorityQueue()
    q.put((10,'a'))
    q.put((-1,'b'))
    q.put((100,'c'))
    print(q.get())
    print(q.get())
    print(q.get())
    '''
    (-1, 'b')
    (10, 'a')
    (100, 'c')
    '''

    信号量

    自定义的互斥锁如果是一个厕所,那么信号量就相当于公共厕所,门口挂着多个厕所的钥匙。抢和释放跟互斥锁一致

    from threading import Thread,Semaphore
    import time
    import random
    sm = Semaphore(5)
    def task(name):
        sm.acquire()
        print('%s正在蹲坑'%name)
        # 模拟蹲坑耗时
        time.sleep(random.randint(1,5))
        sm.release()
    if __name__ == '__main__':
        for i in range(20):
            t = Thread(target=task,args=('伞兵%s号'%i,))
            t.start()
    ‘’‘
    同时进行五个线程操作,超过五个进入等待状态,当有新的线程结束运行等待的线程就会加入
    ‘’‘

    Event事件

    一些线程需要等待另外一些线程运行完毕才能运行,类似汽车过红绿灯

    # event事件
    from threading import Event,Thread
    import time
    event = Event()
    def light():
        print('红灯')
        time.sleep(3)
        event.set()
        print('绿灯')
    def car(i):
        print('%s等红灯'%i)
        event.wait()
        print('%s 绿灯行'%i)
    t1 = Thread(target=light)
    t1.start()
    
    for i in range(5):
        t = Thread(target=car,args=(i,))
        t.start()
    '''
    红灯
    0等红灯
    1等红灯
    2等红灯
    3等红灯
    4等红灯
    绿灯
    1 绿灯行
    2 绿灯行
    4 绿灯行
    3 绿灯行
    0 绿灯行
    '''
  • 相关阅读:
    生成操作 嵌入的资源
    用JavaScript操作CSS滤镜实现最近新闻旁边的“new”
    26个ASP.NET常用性能优化方法
    kafka集群搭建(windows环境下)
    AtCoder Beginner Contest 215 F Dist Max 2(二分、尺取)
    CodeForces 1487C Minimum Ties(建图、模拟)
    C#获取 URL参数
    编程给程序员带来哪些坏习惯
    【转载】IIS和服务器安全设置教程
    [转载]在IE8下动易SiteWeaver后台编辑器按钮没有反应的解决方案
  • 原文地址:https://www.cnblogs.com/yangzhaon/p/10835497.html
Copyright © 2011-2022 走看看