首页 > 解决方案 > Flask 中有 python GIL 吗?

问题描述

我最近在研究python多线程,我发现GIL会强制python一次运行一个线程,即使在多核CPU上也是如此。

所以我做了一些小PoC。

我的代码如下:

import threading
import time

COUNT = 50000000
def count():
    i = 0
    print('thread id =', threading.get_ident())
    while(i < COUNT):
        i = i +1

start_time = time.time()
count()
count()
end_time = time.time()
print(f'execution time without multiple threading : {end_time - start_time}')

start_time = time.time()
t_1 = threading.Thread(target=count)
t_2 = threading.Thread(target=count)
t_1.start()
t_2.start()
t_1.join()
t_2.join()
end_time = time.time()
print(f'execution time with multiple threading : {end_time - start_time}')

这是我的结果:

thread id = 2204
thread id = 2204
execution time without multiple threading : 5.695769786834717
thread id = 3492
thread id = 5260
execution time with multiple threading : 5.339878082275391

这很清楚 GIL 的工作原理。

但现在我在 Flask 上做同样的过程,看起来 GIL 没有按预期工作。这是我的代码:

服务器.py

from flask import Flask
import threading
import os

app = Flask(__name__)
COUNT = 50000000

@app.route('/')
def hello():
    print ('Thread id = ', threading.get_ident())
    print ('Process id = ', os.getpid())
    i = 0
    while(i < COUNT):
        i = i +1
    return "Hello World!"

if __name__ == '__main__':
    app.run()

客户端.py

import requests
import time
import multiprocessing as mp

def send():
    start_time = time.time()
    r = requests.get('http://localhost:5000')
    end_time = time.time()
    print(f'response after {end_time - start_time}')

if __name__ == '__main__':
    p_1 = mp.Process(target=send)
    p_2 = mp.Process(target=send)
    p_1.start()
    p_2.start()
    p_1.join()
    p_2.join()

server.py 的结果:

Thread id =  18428
Process id =  19000
Thread id =  17436
Process id =  19000
127.0.0.1 - - [14/Sep/2020 09:36:19] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [14/Sep/2020 09:36:19] "GET / HTTP/1.1" 200 -

client.py 的结果

response after 7.361770153045654
response after 7.373677015304565

似乎有 2 个客户端同时获得响应,但是使用 GIL,我的预期结果应该是 7.3 第一个响应和 14.xxx 在第二个响应。谁能帮我验证这个问题?

标签: pythonmultithreadingflask

解决方案


Python Flask 中也有一个 GIL 在我问的问题中,我没有单独向服务器发送请求。实际上,单个请求需要一半的时间才能得到响应。为什么我们可以同时得到两个响应?这是因为其中有 sys.getswitchinterval() ,所以线程将每 0.005 秒切换一次,直到它们完成工作。


推荐阅读