zoukankan      html  css  js  c++  java
  • 2018.11.12

    1.GIL Global Interpreter Lock
    全局解释器锁
    锁就是线程里面那个锁
    锁是为了避免资源竞争造成数据的错乱

    python程序的执行过程
    1.启动解释器进程 python.exe
    2.解析你的py文件并执行它

    每个py程序中都必须有解释器参与 解释器其实就是一堆代码
    相当于多个线程要调用同一个解释器代码 共享以为竞争 竞争就要出事
    给解释器加互斥锁

    GIL与自定义互斥锁的区别,多个线程争抢GIL与自定义互斥锁的过程分析

    全局锁不能保证自己开启的线程安全 但是保证解释器中的数据的安全的
    GIL 在线程调用解释器时 自动加锁 在IO阻塞时或线程代码执行完毕时 自动解锁
    GIL不能保证多线程同时对一个文件进行读写时保证数据不错乱.
    自定义互斥锁可以保证数据不错乱.可以自定义给需要的代码进行进行加锁
    python 中内存管理依赖于 GC(一段用于回收内存的代码) 也需要一个线程
    除了你自己开的线程 系统还有一些内置线程 就算你的代码不会去竞争解释器 内置线程也可能会竞争
    所以必须加上锁

    当一个线程遇到了IO 同时解释器也会自动解锁 去执行其他线程 CPU会切换到其他程序

    """
    解释器加锁以后
    将导致所有线程只能并发 不能达到真正的并行 意味着同一时间只有一个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

    在IO密集的程序中 线程更快
    # 计算密集任务
    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)


    2 进程池
    就是一个装进程的容器
    为什么出现
    当进程很多的时候方便管理进程
    什么时候用?
    当并发量特别大的时候 列入双十一
    很多时候进程是空闲的 就让他进入进程池 让有任务处理时才从进程池取出来使用
    进程池使用
    ProcessPoolExecutor类
    创建时指定最大进程数 自动创建进程
    调用submit函数将任务提交到进程池中
    创建进程是在调用submit后发生的

    总结一下:
    进程池可以自动创建进程
    进程限制最大进程数
    自动选择一个空闲的进程帮你处理任务

    进程什么时候算是空闲?
    代码执行完算是空闲

    IO密集时 用线程池
    计算密集时 用进程池

    """
    import socket
    from multiprocessing import Process

    from concurrent.futures import ProcessPoolExecutor

    # 收发数据
    def task(c, addr):
    while True:
    try:
    data = c.recv(1024)
    print(data.decode("utf-8"))
    if not data:
    c.close()
    break
    c.send(data.upper())

    except Exception:
    print("连接断开")
    c.close()
    break

    if __name__ == '__main__':

    server = socket.socket()

    server.bind(("127.0.0.1",65535))

    server.listen(5)

    # 创建一个进程池 默认为CPU个数
    pool = ProcessPoolExecutor()#默认时4个进程

    while True:
    c,addr = server.accept()
    # p = Process(target=task,args=(c,addr))
    # p.start()
    pool.submit(task,c,addr)

    3线程池的写法 和进程池差不多
    #from multiprocessing import cpu_count
    #print(cpu_count()) 可以查看cpu核数
    from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
    from threading import current_thread

    import os,time,random

    def task():
    time.sleep(random.randint(1,2))
    print(current_thread())

    def run():
    # 默认为cpu核心数 * 5
    pool = ThreadPoolExecutor(3)
    for i in range(30):
    pool.submit(task)

    if __name__ == '__main__':
    run()

  • 相关阅读:
    asp.net获取当前页面的url地址
    取多个name值相同的input里面的值
    多线程实践
    《谷物大脑》是骗子写的伪科学书:樊登著作4本,都是3星
    历史远未终结,全球化面临挑战:4星|《世界不是平的》
    大众汽车的恐吓文化导致了排放门:4星|《像职场赢家一样做减法》
    穿越回秦朝能发电吗?能:4星|《1分钟物理》
    作者没有实战经验,案例老旧,图表水平差:2星|《社群思维》
    滴滴优步面临各地竞争对手难以通吃:4星|《哈佛商业评论》第3期
    2星|《重新定义物流》:形式像PPT,内容像公关稿
  • 原文地址:https://www.cnblogs.com/jutao/p/9948604.html
Copyright © 2011-2022 走看看