zoukankan      html  css  js  c++  java
  • 一、GIL全局解释器锁

      1.GIL

        全局解释器锁  只在Cpython解释器中

        GIL本质也是一把互斥锁:将并发变成串行牺牲效率保证数据的安全

        用来阻止同一个进程下的多个线程的同时执行(同一个进程内多个线程无法实现并行但是可以实现并发)

        GIL的存在是因为Cpython解释器的内存管理不是线程安全的

      2.内存管理>>>垃圾回收机制

        (1)引用计数

        (2)标记清楚

        (3)分代回收

      3.同一进程下的多个线程在同一时刻只能有一个线程被执行

      4.线程是直接嫩够被cpu执行吗?

        必须先抢解释器才能被cpu执行

      5.GIL是加在Cpython解释器上的一把锁,并不能保证数据的安全

        如果你想保证数据的安全,就必须加不同的锁

      6.多线程是不是没用?

      例如:四个任务:计算密集的任务  每个任务耗时10s

          单核情况下:

            多线程好一点,消耗的资源少一点

          多核情况下:

            开四个进程:10s多一点

            开四个线程:40s多一点

         四个任务:IO密集的任务  每个任务io 10s

          单核情况下:

            多线程好一点

          多核情况下:

            多线程好一点

        多线程和多进程都有自己的优点,要根据项目需求合理选择

      计算密集型

    from multiprocessing import Process
    from threading import Thread
    import os,time
    def work():
        res=0
        for i in range(100000000):
            res*=i
    
    
    if __name__ == '__main__':
        l=[]
        print(os.cpu_count())  # 本机为8核
        start=time.time()
        for i in range(8):
            # p=Process(target=work) #耗时9.252728939056396
            p=Thread(target=work) #耗时35.369622230529785
            l.append(p)
            p.start()
        for p in l:
            p.join()
        stop=time.time()
        print('run time is %s' %(stop-start))

      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(600):
            p=Process(target=work) #耗时4.699530839920044
            # p=Thread(target=work) #耗时2.054128885269165
            l.append(p)
            p.start()
        for p in l:
            p.join()
        stop=time.time()
        print('run time is %s' %(stop-start))

      7.补充

        TCP实现并发

      客户端

    import socket
    
    
    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    
    while True:
        client.send(b'hello')
        data = client.recv(1024)
        print(data.decode('utf-8'))

      服务端

    """
    服务端
        1.要有固定的IP和PORT
        2.24小时不间断提供服务
        3.能够支持并发
    """
    
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    
    
    def talk(conn):
        while True:
            try:
                data = conn.recv(1024)
                if len(data) == 0:break
                print(data.decode('utf-8'))
                conn.send(data.upper())
            except ConnectionResetError as e:
                print(e)
                break
        conn.close()
    
    while True:
        conn, addr = server.accept()  # 监听 等待客户端的连接  阻塞态
        print(addr)
        t = Thread(target=talk,args=(conn,))
        t.start()

    二、GIL与普通的互斥锁

      对于不同的数据,要想保证安全,需要加不同的锁处理

      GIL并不能保证数据的安全,它是对Cpython解释器加锁,针对的是线程

      保证的是同一个进程下多个线程之间的安全

    from threading import Thread
    import time
    
    n = 100
    
    def task():
        global n
        tmp = n
        # time.sleep(1)
        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)

    三、死锁与递归锁

      1.死锁

        每acquire一次锁身上的计数加1

        每release一次锁身上的计数减1

        只要锁的计数不为0,其他人都不能抢

    from threading import Thread,Lock,current_thread,RLock
    import time
    
    mutexA = Lock()
    mutexB = Lock()
    
    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()

      2.递归锁

        Rlock可以被第一个抢到锁的人连续的acquire和release

    from threading import Thread,Lock,current_thread,RLock
    import time
    
    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()

    四、信号量

      互斥锁:一个厕所(一个坑位)

      信号量:公共厕所(多个坑位)

    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()

    五、event事件

    from threading import Event,Thread
    import time
    import random
    
    
    event = Event()
    
    
    def light():
        print('红灯亮着!')
        time.sleep(3)
        event.set()  # 解除阻塞,给我的event发了一个信号
        print('绿灯亮了!')
    
    
    def car(i):
        print('%s 正在等红灯了'%i)
        event.wait()  # 阻塞
        print('%s 加油门飙车了'%i)
    
    t1 = Thread(target=light)
    t1.start()
    
    
    for i in range(10):
        t = Thread(target=car,args=(i,))
        t.start()

    六、线程queue

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

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

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

      2.Queue  普通q

    import queue
    
    q=queue.Queue(3)
    q.put(1)
    q.put(2)
    q.put(3)
    print(q.get())
    print(q.get())
    print(q.get())

      3.LifoQueue  先进后出q

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

      4.PriorityQueue  优先级q(数值小的先出)

    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())
  • 相关阅读:
    腾讯微博
    城市左右选择添加按钮案例
    jQuery元素操作1
    动态创建表格
    五角星评论案例
    点击图片箭头回到顶部案例
    HDU1506: Largest Rectangle in a Histogram(最大子矩阵,好题动态优化左右边界)
    HDU1165: Eddy's research II(递推)
    HDU1158:Employment Planning(线性dp)
    HDU1081:To The Max(最大子矩阵,线性DP)
  • 原文地址:https://www.cnblogs.com/yljbky/p/11352568.html
Copyright © 2011-2022 走看看