• day36 GIL锁与线程池


    多进程与多线程效率对比

    #
    # """
    #
    #     计算密集型
    # """
    
    # from threading import  Thread
    # from multiprocessing import  Process
    # import time
    #
    # a = 1
    # def task():
    #     global a
    #     for i in range(10000000):
    #         a +=1
    #         a * 10 / 2 - 3
    #
    # s = time.time()
    # #多线程
    # # t1 = Thread(target=task)
    # # t2 = Thread(target=task)
    # # t3 = Thread(target=task)
    #
    # if __name__ == '__main__':
    #
    #     # 多进程
    #     t1 = Process(target=task)
    #     t2 = Process(target=task)
    #     t3 = Process(target=task)
    #     t1.start()
    #     t2.start()
    #     t3.start()
    #
    #     t1.join()
    #     t2.join()
    #     t3.join()
    #
    #     print(time.time() - s)
    #
    
    
    """
    
        IO型任务
    """
    
    
    from threading import  Thread
    from multiprocessing import  Process
    import time
    
    
    def task():
        # for i in range(10):
        with open(r"D:脱产5期内容day34视频1.线程理论.mp4",mode="rb")as f:
            while True:
                data = f.read(1024)
                if not data:
                    break
    
    s = time.time()
    
    if __name__ == '__main__':
        # 多线程
        t1 = Thread(target=task)
        t2 = Thread(target=task)
        t3 = Thread(target=task)
    
        # 多进程
        # t1 = Process(target=task)
        # t2 = Process(target=task)
        # t3 = Process(target=task)
        t1.start()
        t2.start()
        t3.start()
    
        t1.join()
        t2.join()
        t3.join()
    
        print(time.time() - s)

    GIL锁

    什么是GIL
        全局解释器锁,是加在解释器上的互斥锁
        只存在于cpython解释器中
        
        python的内存回收管理机制,简称GC

    GIL的加锁与解锁时机

    加锁的时机:在调用解释器时立即加锁
    解锁时机:
        当前进程遇到IO或超时
    
    为什么需要GIL
        由于cpython的内存管理是非线程安全的,于是cpython就给解释器加了个锁,解决了安全问题,但是降低了效率,虽然有解决方  案,但是由于牵涉太多,一旦被修改,很多以前的基于GIL的程序都需要修改,所以变成了历史遗留问题
    
    
    GIL带来的问题
        即使在多核处理器情况下,也无法真正的并行
        先有多线程模块,有这个问题,所以后来有了多进程模块弥补这个问题
    
    总结:
        1.在单核情况下,无论是IO密集型还是计算密集,HIL都不会产生影响
        2.如果是多核下,IO密集型会受到GIl的影响,但是很明显IO速度比计算速度慢
        3.IO密集型多线程, 因为多线程开销小,节省资源,对于计算密集型,应该使用多进程,因为在cpytho中多线程是无法并行的

    GIL与线程锁的区别

    from threading import  Thread,Lock
    import time
    
    lock = Lock()
    a = 0
    def task():
        global a
        lock.acquire()
        temp = a
        time.sleep(0.01)
        a = temp + 1
        lock.release()
    
    ts = []
    for i in range(10):
        t1 = Thread(target=task)
        t1.start()
        ts.append(t1)
    
    for i in ts:
        i.join()
    
    print(a)
    
    
    GIL使用用于保护解释器相关的数据,解释器也是一段程序,肯定有其定义各种数据
    
    GIL并不能保证自己定义的数据的安全,所有一旦
    
    多核cpu中,进程可以并行,线程不能并行

    多线程TCP

    客户端
    from threading import Thread
    import socket
    
    c = socket.socket()
    c.connect(("127.0.0.1",8989))
    
    def send_msg():
        while True:
            msg = input(">>>:")
            if not msg:
                continue
            c.send(msg.encode("utf-8"))
    
    send_t = Thread(target=send_msg)
    send_t.start()
    
    while True:
        try:
            data = c.recv(1024)
            print(data.decode("utf-8"))
        except:
            c.close()
            break
    
    服务器端
    from concurrent.futures import ThreadPoolExecutor
    from threading import  Thread
    import socket
    
    server = socket.socket()
    server.bind(("127.0.0.1",8989))
    server.listen()
    
    
    pool = ThreadPoolExecutor(3)
    
    def task(client):
        while True:
            try:
                data = client.recv(1024)
                if not data:
                    client.close()
                    break
                client.send(data.upper())
            except Exception:
                client.close()
                break
    
    while True:
        client,addr = server.accept()
        # t = Thread(target=task,args=(client,))
        # t.start()
        pool.submit(task,client)

    线程池与进程池

    池为容器,本质上就是一个存储进程或线程的列表
    
    from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
    from  threading import active_count,current_thread
    import os,time
    # 创建线程池 指定最大线程数为3  如果不指定 默认为CPU核心数 * 5
    # pool = ThreadPoolExecutor(3)# 不会立即开启子线程
    #
    # print(active_count())
    #
    # def task():
    #     print("%s running.." % current_thread().name)
    #     time.sleep(1)
    #
    # #提交任务到线程池
    # for i in range(10):
    #     pool.submit(task)
    #
    
    
    # 创建进程池 最大进程数为3 默认为cpu个数
    pool = ProcessPoolExecutor(3)# 不会立即开启子进程
    
    # time.sleep(10)
    
    def task():
        print("%s running.." % os.getpid())
        time.sleep(1)
    
    if __name__ == '__main__':
        # #提交任务到进程池
        for i in range(10):
            pool.submit(task) # 第一次提交任务时会创建进程  ,后续再提交任务,直接交给以及存在的进程来完成,如果没有空闲进程就等待
    
    
    # 与信号量的区别 ,信号量也是一种锁 适用于保证同一时间能有多少个进程或线程访问
    # 而线程/进程池,没有对数据访问进行限制仅仅是控制数量

    同步与异步

    """
    阻塞 非阻塞
    程序遇到了IO操作,无法继续执行代码,叫做阻塞
    程序没有遇到IO操作,正常执行中,就叫非阻塞
    它们指的是程序的状态
    
        就绪  运行  阻塞
    
    就绪和阻塞给人的感觉就是卡主了
    
    
    同步 异步
    同步(调用/执行/任务/提交),发起任务后必须等待任务结束,拿到一个结果才能继续运行
    异步                     发起任务后不需要关系任务的执行过程,可以继续往下运行
    
    异步效率高于同步
    但是并不是所有任务都可以异步执行,判断一个任务是否可以异步的条件是,任务发起方是否立即需要执行结果
    
    
    同步不等于阻塞  异步不等于非阻塞
    当使用异步方式发起任务时 任务中可能包含io操作  异步也可能阻塞
    同步提交任务 也会卡主程序 但是不等同阻塞,因为任务中可能在做一对计算任务,CPU没走
    """
    
    # 使用线程池 来执行异步任务
    
    from concurrent.futures import ThreadPoolExecutor
    import time
    pool = ThreadPoolExecutor()
    
    
    def task(i):
    
        time.sleep(1)
        print("sub thread run..")
        i += 100
        return i
    
    fs = []
    for i in range(10):
        f = pool.submit(task,i) # submit就是一异步的方式提交任务
        # print(f)
        # print(f.result()) # result是阻塞的 会等到这任务执行完成才继续执行 ,会异步变成同步
        fs.append(f)
    
    
    
    # 是一个阻塞函数,会等到池子中所有任务完成后继续执行
    pool.shutdown(wait=True)
    
    # pool.submit(task,1) # 注意 在shutdown之后 就不能提交新任务了
    
    for i in fs:
        print(i.result())
    
    print("over")

    使用线程池 来发起异步任务

    阻塞函数
    pool.shutdown()
    
    同步不是阻塞,异步也不完全是非阻塞,也有可能阻塞
  • 相关阅读:
    Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis.
    DHCP "No subnet declaration for xxx (no IPv4 addresses)" 报错
    Centos安装前端开发常用软件
    kubernetes学习笔记之十:RBAC(二)
    k8s学习笔记之StorageClass+NFS
    k8s学习笔记之ConfigMap和Secret
    k8s笔记之chartmuseum搭建
    K8S集群集成harbor(1.9.3)服务并配置HTTPS
    Docker镜像仓库Harbor1.7.0搭建及配置
    Nginx自建SSL证书部署HTTPS网站
  • 原文地址:https://www.cnblogs.com/shanau2/p/10214584.html
Copyright © 2020-2023  润新知