zoukankan      html  css  js  c++  java
  • GIL 进程池与线程池

    一.全局解释器锁

      1.GIL:全局解释器锁

        GIL本质就是一把互斥锁,是夹在解释器身上的

        统一进程内的所有线程都需要先抢到GIL锁,才能执行pai解释器代码

      2.GIL优缺点:

        优点:

          保证Cpython解释器内存管理的线程安全

        缺点:

          同一进程内所有的线程同一时刻只能有一个执行,

          也就是锁Cpython解释器多线程无法实现真正的并行

    from threading import Thread,current_thread
    import time
    
    def task():
        print("%s is running"%current_thread().name)
        time.sleep(3)
        print("%s is done"current_thread().name)
    
    if __name__=="__main__":
        t1=Thread(target=task)
        t2=Thread(target=task)
        t3=Thread(target=task)
        t1.start()
        t2.start()
        t3.start()

    二.Cpython解释器并发效率验证

    关于GIL性能的讨论

    解释器加锁以后
    将导致所有线程只能并发 不能达到真正的并行 意味着同一时间只有一个CPU在处理你的线程
    给你的感觉是效率低

    代码执行有两种状态
    阻塞 i/o 失去CPU的执行权 (CPU等待IO完成)
    非阻塞 代码正常执行 比如循环一千万次 中途CPU可能切换 很快会回来 (CPU在计算)

    假如有32核CPU 要处理一个下载任务 网络速度慢 100k/s 文件大小为1024kb
    如果你的代码中IO操作非常多 cpu性能不能直接决定你的任务处理速度


    案例:
    目前有三个任务 每个任务处理需一秒 获取元数据需要一小时
    3个CPU 需要 一小时1秒
    1个cpu 需要 一小时3秒


    在IO密集的程序中 CPU性能无法直接决定程序的执行速度 python就应该干这种活儿
    在计算密集的程序中 CPU性能可以直接决定程序的执行速度

    #计算密集型测试
    from
    threading import Thread from multiprocessing import Process import time # 计算密集任务 def task1(): sum = 1 for i in range(10000000): sum *= i def task2(): sum = 1 for i in range(10000000): sum *= i def task3(): sum = 1 for i in range(10000000): sum *= i def task4(): sum = 1 for i in range(10000000): sum *= i def task5(): sum = 1 for i in range(10000000): sum *= i def task6(): sum = 1 for i in range(10000000): sum *= i if __name__ == '__main__': # 开始时间 st_time = time.time() # 多线程情况下 # t1 = Thread(target=task1) # t2 = Thread(target=task2) # t3 = Thread(target=task3) # t4 = Thread(target=task4) # t5 = Thread(target=task5) # t6 = Thread(target=task6) t1 = Process(target=task1) t2 = Process(target=task2) t3 = Process(target=task3) t4 = Process(target=task4) t5 = Process(target=task5) t6 = Process(target=task6) t1.start() t2.start() t3.start() t4.start() t5.start() t6.start() # # t1.join() # t2.join() # t3.join() # t4.join() # t5.join() # t6.join() print(time.time() - st_time)
    from threading import Thread
    from multiprocessing import Process
    import time
    
    
    # 计算密集任务
    def task1():
        time.sleep(3)
    
    
    def task2():
        time.sleep(3)
    
    
    def task3():
        time.sleep(3)
    
    
    def task4():
        time.sleep(3)
    
    
    def task5():
        time.sleep(3)
    
    
    def task6():
        time.sleep(3)
    
    if __name__ == '__main__':
    
        # 开始时间
        st_time = time.time()
        # 多线程情况下
        # t1 = Thread(target=task1)
        # t2 = Thread(target=task2)
        # t3 = Thread(target=task3)
        # t4 = Thread(target=task4)
        # t5 = Thread(target=task5)
        # t6 = Thread(target=task6)
    
    
        t1 = Process(target=task1)
        t2 = Process(target=task2)
        t3 = Process(target=task3)
        t4 = Process(target=task4)
        t5 = Process(target=task5)
        t6 = Process(target=task6)
    
        t1.start()
        t2.start()
        t3.start()
        t4.start()
        t5.start()
        t6.start()
    
        # t1.join()
        # t2.join()
        # t3.join()
        # t4.join()
        # t5.join()
        # t6.join()
    
        print(time.time() - st_time)

    三.GIL与互斥锁

    from  threading import Thread,Lock
    import time
    
    mutex = Lock()
    num = 1
    def task():
        global num
        # print(num)
        mutex.acquire()
        temp = num
        print(temp)
        time.sleep(1)   # 当你们线程中出现io时 GIL锁就解开
        num = temp + 1
        mutex.release()  # 线程任务结束时GIL锁解开
    
    
    t1 = Thread(target=task,)
    
    t2 = Thread(target=task,)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(num)

    GIL 和自定义互斥锁的区别

    全局锁不能保证自己开启的线程安全 但要保证解释器中的数据的安全

    GIL 在线程调用解释器是 自动加锁 在IO阻塞时或线程执行完毕时 自动解锁

    四.进程池和线程池

      进程池

        就是一个装进程的容器

      为什么出现

        当进程很多的时候方便管理进程

      什么时候用?

        当并发量特别大的时候 列入双十一

        很多时候进程是空闲的 就让他进入进程池 让有任务处理时才从进程取出来使用

      进程池使用

        ProcessPoolExecutor类

        创建时指定最大进程数 自动创建进程

        调用submit函数将任务提交进程池中

        创建进程是在调用submit后发生

      总结一下:

        进程池可以自动创造进程

        进程现在最大进程数

        自动选择一个空闲的进程帮你处理任务

      进程什么时候算是空闲?

        代码执行完算是空闲

      IO密集时 用线程池

      计算密集时 用线程池

     思考

    1、什么是GIL

    GIL = Global Interpreter Lock (全局解释锁器锁)
    2、有了GIL会对单进程下的多个线程造成什么样的影响

    防止对个线程竞争统一资源造成数据的错乱,只能有一个线程进行读写操作.
    3、为什么要有GIL

    为了避免资源竞争造成的数据错乱
    4、GIL与自定义互斥锁的区别,多个线程争抢GIL与自定义互斥锁的过程分析

    GIL不保证自己开启线程的安全 但保证解释器中数据的安全

    GIL 在线程调用解释其时 自动加锁 在IO阻塞是或线程代码执行完毕时,自动解锁
    5、什么时候用python的多线程,什么时候用多进程,为什么?

    2、进程池与线程池
    1、池的用途,为何要用它

    池用来存储线程和进程,可以方便进程和线程的管理
    2、池子里什么时候装进程什么时候装线程?

    计算密集时装进程,IO密集时装线程

    3、基于进程池与线程池实现并发的套接字通信

    #服务端
    
    from socket import *
    from threading import Thread
    from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
    
    tpool=ThreadPoolExecutor(3)
    
    def communicte(conn,client_addr):
        while True:
            try:
                data= conn.recv(1024)
                if not data:break
                conn.send(data.upper())
            except ConnectionAbortedError:
                break
        conn.close()
    
    def server():
        server = socket(AF_INET,SOCK_STREAM)
        server.bind(('127.0.0.1',8080))
        server.listen(5)
    
        while True:
            conn,client_addr=server.accept()
            print(client_addr)
            tpool.submit(communicte,conn,client_addr)
        server.close()
    
    if __name__=='__main__':
        server()
    #客户端
    import socket
    
    c = socket.socket()
    c.connect(('127.0.0.1',8080))
    while True:
        msg = input(">>>:")
        c.send(msg.encode("utf-8"))
        data = c.recv(1024)
        print(data.decode("utf-8"))
  • 相关阅读:
    ubuntu golang nginx
    如何写易于调试的代码
    Topic 2: golang string operation
    topic 1: golang file operation
    【转帖】ArtisticStyle----很好用的C/C++样式格式化工具
    【转帖】C++经典书籍汇总
    (转载)MonoBehaviour的事件和具体功能总结
    unity3d的延时调用函数
    unity3D 实现手机的双指触控和Input类touch详解
    Lua 关于"."与":"号的用法区别
  • 原文地址:https://www.cnblogs.com/gongcheng-/p/9949165.html
Copyright © 2011-2022 走看看