zoukankan      html  css  js  c++  java
  • 使服务器支持并发、GIL全局解释器锁、死锁和Rlock、信号量、event事件、

    服务器的并发实现:

    服务端:

    import socket
    from threading import Thread
    
    """
    服务端
        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循环中的代码,
    开启一个线程去服务这个客户端,当有客户端再过来连的时候,
    可以再开启一个线程去服务一个客户端
    """
    while True:
        conn, addr = server.accept()  # 监听 等待客户端的连接  阻塞态
        print(addr)
        t = Thread(target=talk, args=(conn,))
        t.start()
    View Code

    客户端:

    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'))
    View Code

    GIL全局解释器锁:

    Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行。

    虽然 Python 解释器中可以“运行”多个线程,但在任意时刻只有一个线程在解释器中运行。

    对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。

    GIL本质也是一把互斥锁:将并发变成串行牺牲效率保证数据的安全
    用来阻止同一个进程下的多个线程的同时执行(同一个进程内多个线程无法实现并行但是可以实现并发)

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

    如果同时运行,那么线程中的值可能还没有被使用就被垃圾回收机制进行回收了,所以CPython解释器的内存管理不是线程安全的,要有GIL。

    垃圾回收机制

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

    研究python的多线程是否有用需要分情况讨论:

    四个任务 计算密集型
    单核情况下
    开线程更省资源
    多核情况下
    开进程 
    开线程

    四个任务 IO密集型
    单核情况下
    开线程更节省资源
    多核情况下
    开线程更节省资源

    代码验证:

    计算密集型:

    计算密集型
    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())  # 本机为6核
        start=time.time()
        for i in range(6):
            # p=Process(target=work) #耗时  4.732933044433594
            p=Thread(target=work) #耗时 22.83087730407715
            l.append(p)
            p.start()
        for p in l:
            p.join()
        stop=time.time()
        print('run time is %s' %(stop-start))
    View Code

    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()) #本机为6核
        start=time.time()
        for i in range(40):
            # p=Process(target=work) #耗时9.001083612442017s多,大部分时间耗费在创建进程上
            p=Thread(target=work) #耗时2.051966667175293s多
            l.append(p)
            p.start()
        for p in l:
            p.join()
        stop=time.time()
        print('run time is %s' %(stop-start))
    View Code

     死锁和Rlock:

    死锁状态:也就是不同线程都去等待对方去释放锁的情况(互相僵持)

    建议:轻易不要去尝试处理锁的问题。

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

    信号量:

    过程:

    先有五个线程同时获得锁,然后运行完因为不同线程睡眠时间不同所以释放时间也会不同,
    之后先释放出来的锁便可以让其他线程再去抢夺。

    # 信号量可能在不同的领域中 对应不同的知识点
    """
    互斥锁:一个厕所(一个坑位)
    信号量:公共厕所(多个坑位)
    """
    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()
    View Code

    envent事件:

    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()
    """
    先启一个线程,打印路灯亮了,进入睡眠的同时,起了十个线程,之后打印正在等绿灯,
    之后等待e.wait()收到信号,当运行e.set()发信号时,便可以继续运行了。
    """
    View Code

    线程queue:

    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())
    View Code
  • 相关阅读:
    设计模式笔记——策略模式(Strategy Pattern)
    C#基础笔记——集合和LINQ
    C#基础笔记——命名规范
    C#基础笔记——语言基础
    C#基础笔记——代码整洁
    C#基础笔记——序列化(Serialize)和反序列化(NonSerialize)
    C#基础笔记——资源管理
    C#基础笔记——协变(Covariance)和逆变(Contravariance)
    C#基础笔记——委托(Delegate)和事件(Event)
    C#基础笔记——泛型(Genericity)
  • 原文地址:https://www.cnblogs.com/yangjiaoshou/p/11353187.html
Copyright © 2011-2022 走看看