GIL,进程池,线程池

GIL与Python多线程

GIL Global Interpreter Lock

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

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

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

python中内存管理依赖于GC(一段用于回收内存的代码)也需要一个线程
除了你自己开的线程 系统还有一些内置线程 就算你的代码不会去竞争解释器 内置也可以所以必须加上锁

当一个线程遇到了IO 同时解释器也会自动解锁 去执行其他线程 cpu会切换到其他程序
x = obj +1
a = obj +1
x = None - 1
a = None - 1

关于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)


IO密集测试

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阻塞时或线程代码执行完毕时 自动解锁
#


TCP客户端

import socket

c = socket.socket()
c.connect(("127.0.0.1", 65535))
while True:
    msg = input(">>>:")
    c.send(msg.encode("utf-8"))
    data = c.recv(1024)
    print(data.decode("utf-8"))



进程池

"""
    进程池
        就是一个装进程的容器
    为什么出现
        当进程很多的时候方便管理进程
    什么时候用?
        当并发量特别大的时候  列入双十一
        很多时候进程是空闲的 就让他进入进程池  让有任务处理时才从进程池取出来使用
    进程池使用
        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()

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




进程什么时候算是空闲




from concurrent.futures import  ProcessPoolExecutor

import os,time,random

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

def run():
    pool = ProcessPoolExecutor(2)
    for i in range(30):
        pool.submit(task)

if __name__ == '__main__':
    run()

线程池





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





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值