七橼77

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  1. 死锁现象与递归锁

    死锁现象举例
    
    from threading import Thread
    from threading import Lock
    import time
    
    lock_A = Lock()
    lock_B = Lock()
    
    class MyThread(Thread):
        def run(self):
            self.f1()
            self.f2()
    
        def f1(self):
            lock_A.acquire()
            print(f'{self.name}抢到了A锁')
            lock_B.acquire()
            print(f'{self.name}抢到了B锁')
            lock_B.release()
            lock_A.release()
        def f2(self):
            lock_B.acquire()
            print(f'{self.name}抢到了B锁')
            time.sleep(0.1)
            lock_A.acquire()
            print(f'{self.name}抢到了A锁')
            lock_A.release()
            lock_B.release()
    if __name__ == '__main__':
        for i in range(3):
            t = MyThread()
            t.start()
    

    1566547259659

    递归锁
    # 递归锁有一个计数的功能, 原数字为0,上一次锁,计数+1,释放一次锁,计数-1,
    # 只要递归锁上面的数字不为零,其他线程就不能抢锁.
    #递归锁可以解决死锁现象,业务需要多个锁时,先要考虑递归锁
    
    from threading import Thread
    from threading import RLock
    import time
    
    lock_A = lock_B = RLock()
    
    
    class MyThread(Thread):
        def run(self):
            self.f1()
            self.f2()
    
        def f1(self):
            lock_A.acquire()
            print(f'{self.name}抢到了A锁')
            lock_B.acquire()
            print(f'{self.name}抢到了B锁')
            lock_B.release()
            lock_A.release()
        def f2(self):
            lock_B.acquire()
            print(f'{self.name}抢到了B锁')
            time.sleep(0.1)
            lock_A.acquire()
            print(f'{self.name}抢到了A锁')
            lock_A.release()
            lock_B.release()
    if __name__ == '__main__':
        for i in range(3):
            t = MyThread()
            t.start()
    
  2. 信号量

    2.1 引入Semaphore模块,Semaphore(5)相当于有五把锁同时让人去抢到,之后释放掉几把锁就会有几把锁被抢

    2.2 也是一种锁,控制并发数量

    from threading import Thread,Semaphore,current_thread
    import time
    import random
    sem = Semaphore(5)
    def task():
        sem.acquire()
        print(f'{current_thread().name} 厕所ing')
        time.sleep(random.randint(1,3))
    
        sem.release()
    if __name__ == '__main__':
        for i in range(20):
            t = Thread(target=task,)
            t.start()
    
  3. GIL全局解释器锁

    1. 好多自称大神的说,GIL锁就是python的致命缺陷,Python不能多核,并发不行等等 .....

      1566547908378

    2. 理论上来说:单个进程的多线程可以利用多核.但是,开发Cpython解释器的程序员,给进入解释器的线程加了锁.1566547928207

    3. 为什么加锁?

      1. 当时都是单核时代,而且cpu价格非常贵.
      2. 如果不加全局解释器锁, 开发Cpython解释器的程序员就会在源码内部各种主动加锁,解锁,非常麻烦,各种死锁现象等等.他为了省事儿,直接进入解释器时给线程加一个锁.
      3. 优点: 保证了Cpython解释器的数据资源的安全.
      4. 缺点: 单个进程的多线程不能利用多核.
    4. Jpython没有GIL锁.pypy也没有GIL锁.

    5. 现在多核时代, 我将Cpython的GIL锁去掉行么?

      1. 因为Cpython解释器所有的业务逻辑都是围绕着单个线程实现的,去掉这个GIL锁,几乎不可能.1566547961588
      2. 单个进程的多线程可以并发,但是不能利用多核,不能并行.
      3. 多个进程可以并发,并行.
      4. io密集型:1566547980018
      5. 计算密集型:1566547995439
  4. GIL与lock锁的区别

    1. 相同点: 都是同种锁,互斥锁.

    2. 不同点:

      ​ 1. GIL锁全局解释器锁,保护解释器内部的资源数据的安全.

      ​ 2. GIL锁 上锁,释放无需手动操作.

      ​ 3. 自己代码中定义的互斥锁保护进程中的资源数据的安全.

      ​ 4. 自己定义的互斥锁必须自己手动上锁,释放锁.1566548019018

  5. 验证计算密集型IO密集型的效率

    1. o密集型:

    1566548054638

    1. 计算密集型:

    1566548075660

    1. 代码验证:

      1. 计算密集型:多进程并发并行效率高
      from threading import Thread
      from multiprocessing import Process
      import random
      import time
      ##计算密集型:单个进程的多线程并发vs多个进程并发,并行
      def task():
          count = 0
          for i in range(100000000):
              count += 1
      #多进程的并发,并行
      if __name__ == '__main__':
          # start_time = time.time()
          # l1 = []
          # for i in range(4):
          #     p = Process(target=task)
          #     l1.append(p)
          #     p.start()
          # for i in l1:
          #     i.join()
          # print(f'执行效率:{time.time()-start_time}')#执行效率:14.23704481124878
      
          #多线程并发
          start_time = time.time()
          l1 = []
          for i in range(4):
              p = Thread(target=task)
              l1.append(p)
              p.start()
          for e in l1:
              e.join()
          print(f'执行效率:{time.time()-start_time}')#执行效率:25.48371386528015
         
      
      1. IO密集型:单个进程多线程并发效率高
      from threading import Thread
      from multiprocessing import Process
      import random
      import time
      def task():
          count = 0
          time.sleep(random.randint(1,3))
          count += 1
      #多进程的并发,并行
      # if __name__ == '__main__':
          # start_time = time.time()
          # l1 = []
          # for i in range(50):
          #     p = Process(target=task,)
          #     l1.append(p)
          #     p.start()
          # for e in l1:
          #     e.join()
          # print(f'执行效率:{time.time()-start_time}')#执行效率:5.1458330154418945
      #单个进程多线程并发
      if __name__ == '__main__':
          start_time = time.time()
          li = []
          for i in range(50):
              t = Thread(target=task,)
              li.append(t)
              t.start()
          for e in li:
              e.join()
          print(f'执行效率:{time.time()-start_time}')#执行效率:3.0080912113189697
      
      
    2. 计算密集型:

  6. 多线程实现socket通信

    1. 无论是多线程还是多进程,如果按照上面的写法,来一个客户端请求,我就开一个线程,来一个请求开一个线程,
    2. 应该是这样: 你的计算机允许范围内,开启的线程进程数量越多越好.
    server端
    
    import socket
    from threading import Thread
    
    
    def communicate(conn,addr):
        while 1:
            try:
                from_client_data = conn.recv(1024)
                print(f'收到来自客户端{addr[0]}的信息:{from_client_data.decode("utf-8")}')
    
                to_client_data = input('>>>').strip()
                conn.send(to_client_data.encode('utf-8'))
            except Exception:
                break
        conn.close()
    def _accept():
        server = socket.socket()
        
        server.bind(('127.0.0.1', 8849))
        
        server.listen(5)
        while 1:
            conn, addr = server.accept()
            t = Thread(target=communicate,args=(conn,addr))
            t.start()
    if __name__ == '__main__':
        _accept()
    
    client端
    
    import socket
    client = socket.socket()
    client.connect(('127.0.0.1',8849))
    while 1:
            try:
                to_server_data = input('>>>').strip()
                client.send(to_server_data.encode('utf-8'))
    
                from_server_data = client.recv(1024)
                print(f'来自客户端的消息:{from_server_data.decode("utf-8")}')
    
            except Exception:
                break
    client.close()
    
  7. 进程池,线程池

    1. 线程池: 一个容器,这个容器限制住你开启线程的数量,比如4个,第一次肯定只能并发的处理4个任务,只要有任务完成,线程马上就会接下一个任务.
    2. 以时间换空间.
    from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
    import os
    import time
    import random
    
    # print(os.cpu_count())
    def task(n):
        print(f'{os.getpid()} 接客')
        time.sleep(random.randint(1,3))
    
    
    if __name__ == '__main__':
    
        # 开启进程池  (并行(并行+并发))
        # p = ProcessPoolExecutor()  # 默认不写,进程池里面的进程数与cpu个数相等
        #
        # # p.submit(task,1)
        # # p.submit(task,1)
        # # p.submit(task,1)
        # # p.submit(task,1)
        # # p.submit(task,1)
        # # p.submit(task,1)
        # # p.submit(task,1)
        # for i in range(20):
        #     p.submit(task,i)
        #
        # 开启线程池  (并发)
        t = ThreadPoolExecutor()  # 默认不写, cpu个数*5 线程数
        # t = ThreadPoolExecutor(100)  # 100个线程
    
        for i in range(20):
            t.submit(task,i)
    

    结合:

    server
    from concurrent.futures import ThreadPoolExecutor
    from threading import Thread
    import socket
    
    def communicate(conn,addr):
        while 1:
            try:
                from_client_data = conn.recv(1024)
                print(f'收到来自客户端{addr}的信息:{from_client_data.decode("utf-8")}')
    
                to_client_data = input('>>>').strip()
                conn.send(to_client_data.encode('utf-8'))
            except Exception:
                break
        conn.close()
    def _accept():
        server = socket.socket()
    
        server.bind(('127.0.0.1', 8840))
    
        server.listen(5)
    
        a = ThreadPoolExecutor(2)
        while 1:
            conn, addr = server.accept()
            t = Thread(target=communicate,args=(conn,addr))
            a.submit(communicate,conn,addr)
    
    if __name__ == '__main__':
        _accept()
    
    import socket
    client = socket.socket()
    client.connect(('127.0.0.1',8840))
    while 1:
            try:
                to_server_data = input('>>>').strip()
                client.send(to_server_data.encode('utf-8'))
    
                from_server_data = client.recv(1024)
                print(f'来自客户端的消息:{from_server_data.decode("utf-8")}')
    
            except Exception:
                break
    client.close()
posted on 2019-08-24 10:20  七橼77  阅读(302)  评论(0编辑  收藏  举报