zoukankan      html  css  js  c++  java
  • 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()
    
    同步不是阻塞,异步也不完全是非阻塞,也有可能阻塞
  • 相关阅读:
    第10组 Beta冲刺(2/4)
    第10组 Beta冲刺(1/4)
    第10组 Alpha冲刺(4/4)
    第08组 Beta版本演示
    第08组 Beta冲刺(4/4)
    第08组 Beta冲刺(3/4)
    第08组 Beta冲刺(2/4)
    第08组 Beta冲刺(1/4)
    第08组 Alpha事后诸葛亮
    第08组 Alpha冲刺(4/4)
  • 原文地址:https://www.cnblogs.com/shanau2/p/10214584.html
Copyright © 2011-2022 走看看