You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何这段Flask代码表现出异步运行特性?IO绑定请求疑问

Flask单线程处理请求的认知矛盾解惑

我原本计划在Flask中使用asyncio与aiomysql,因此开展了一项简单实验,但遇到了认知矛盾点。我一直认为Flask以单线程顺序处理请求,当处理IO绑定请求时,无法同时处理其他请求,但实际结果与该认知不符,特此请教其中原因。

实验代码

from flask import Flask, Response, jsonify
import asyncio
import aiomysql
import pymysql

app = Flask(__name__)

# 注:代码中未展示conn的初始化逻辑,推测是提前创建了pymysql连接
@app.route('/sync2')
def hihi2():
    print('IO bound start!')
    cur = conn.cursor()
    cur.execute('''select Count(*)
    from fruit_defect
    WHERE date between '2022-11-22' and '2022-11-25'
    ''')
    print('IO Bound finish!')
    result = cur.fetchall()
    print(result)
    cur.close()
    return jsonify(result)

@app.route('/sync3')
def hihi3():
    print('CPU BOUND start!')
    c = 0
    for _ in range(1000000):
        c += 1
    print('CPU bound finish!')
    
    return jsonify(1)

实验结果

同时发起对/sync2(IO绑定请求)和/sync3(CPU绑定请求)的请求后,控制台输出顺序如下:

  1. IO bound start!
  2. CPU BOUND start!
  3. CPU bound finish!
  4. IO Bound finish!

可见/sync3的CPU密集任务在/sync2的IO等待期间完成了,说明两个请求被同时处理。

原因分析

  • Flask默认开发服务器的多线程配置:
    Flask默认使用的Werkzeug开发服务器,在调试模式(debug=True)下默认开启多线程(threaded=True)。这意味着服务器会创建多个线程来处理并发请求,当某个线程在等待IO(比如数据库查询)时,其他线程可以继续处理新的请求,所以你看到了并发处理的现象。

  • 单线程模式的验证方式:
    如果你想验证Flask单线程下的阻塞行为,需要在启动时显式关闭多线程:

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

    此时再测试,/sync2的IO请求会阻塞整个服务器,/sync3必须等/sync2完成后才能开始处理。

  • 同步数据库连接的影响:
    你的代码中使用的是同步的pymysql而非异步的aiomysql,所以/sync2是同步IO操作,但因为服务器是多线程,所以其他线程可以并行处理/sync3的请求,这进一步强化了并发的表现。

总结

你的核心认知(单线程Flask会在IO绑定请求时阻塞其他请求)是正确的,但忽略了Flask默认开发服务器在调试模式下的多线程默认配置,导致实验结果与预期不符。若要测试单线程下的阻塞逻辑,需显式设置threaded=False。

内容的提问来源于stack exchange,提问作者KIM Bucket

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 22:42:59