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

python-telegram-bot异步命令线程包装器引发NoneType await异常

问题分析

报错的核心原因是:你写的asyncbot装饰器返回的是None,而python-telegram-bot v20+的命令处理器要求返回可被await的协程对象。当框架尝试await这个处理器时,发现拿到的是None,直接触发TypeError: object NoneType can't be used in 'await' expression。

另外你的实现思路完全走偏了:python-telegram-bot基于asyncio构建,处理耗时任务根本不需要手动开线程,强行这么做反而会破坏asyncio的事件循环机制,还可能引发线程安全问题(官方明确说库不保证线程安全)。

正确解决方案

分两种场景给出对应处理方式:

场景1:IO密集型耗时任务(比如网络请求、文件读写)

直接用asyncio.create_task把任务丢到后台执行,不会阻塞主事件循环:

import asyncio
from telegram import Update
from telegram.ext import ContextTypes

async def test(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    # 先给用户发即时响应,避免用户以为Bot没反应
    await update.message.reply_text("任务已启动,完成后会通知你")
    # 创建后台异步任务
    asyncio.create_task(long_running_io_job(update, context))

async def long_running_io_job(update: Update, context: ContextTypes.DEFAULT_TYPE):
    # 模拟IO耗时操作,必须用async版本的sleep(如果是真实IO,也要用异步库)
    await asyncio.sleep(20)
    # 任务完成后通知用户
    await update.message.reply_text("任务执行完毕!")

场景2:CPU密集型耗时任务(比如大量计算)

CPU密集任务会阻塞asyncio事件循环,这时候可以用asyncio.to_thread(Python3.9+)或者线程池来把任务放到单独线程执行:

方式一:用asyncio.to_thread(推荐)

import asyncio
import time
from telegram import Update
from telegram.ext import ContextTypes

async def test(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    await update.message.reply_text("CPU密集任务开始执行")
    # 把CPU任务丢到线程中执行
    await asyncio.to_thread(long_running_cpu_job, update, context)
    await update.message.reply_text("CPU密集任务完成")

def long_running_cpu_job(update: Update, context: ContextTypes.DEFAULT_TYPE):
    # 模拟CPU密集操作,用普通time.sleep即可
    time.sleep(20)
    # 注意:如果要在这个线程里调用Telegram API,建议通过主线程的回调处理,避免线程安全问题

方式二:自定义线程池

import asyncio
import time
from concurrent.futures import ThreadPoolExecutor
from telegram import Update
from telegram.ext import ContextTypes

# 全局线程池,根据服务器配置调整worker数量
executor = ThreadPoolExecutor(max_workers=4)

async def test(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    await update.message.reply_text("CPU密集任务开始执行")
    loop = asyncio.get_running_loop()
    # 提交任务到线程池
    await loop.run_in_executor(executor, long_running_cpu_job, update, context)
    await update.message.reply_text("CPU密集任务完成")

def long_running_cpu_job(update: Update, context: ContextTypes.DEFAULT_TYPE):
    time.sleep(20)
原代码的问题拆解
  1. 装饰器返回None:你的asyncbot装饰器里,wrapper函数没有返回值,默认返回None。而python-telegram-bot调用处理器时,期望得到一个协程对象,await None自然会报错。
  2. 错误的线程使用方式:手动创建Thread并在里面调用asyncio.run,会在新线程启动独立的asyncio事件循环,既浪费资源,又违反了库的线程安全要求,完全没必要。

内容的提问来源于stack exchange,提问作者gang tang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 03:38:18