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

如何使用tormysql实现异步URL插入?yield控制流相关疑问

解决tormysql异步插入URL到数据库的问题

看起来你卡在了异步插入的执行环节,核心问题大概率是协程没有被正确调度,或者对tormysql的异步流程和yield的用法理解有偏差。我来一步步帮你解决:

首先,明确tormysql的异步核心逻辑

tormysql是基于Tornado协程的异步MySQL驱动,所有IO操作(拿连接、执行SQL、提交事务)都是异步的,必须通过yield(旧版Tornado)或await(新版Tornado)来等待操作完成;同时,协程函数需要被Tornado的IOLoop调度才能真正执行——直接调用协程函数只会生成一个协程对象,不会跑起来。

第一步:正确初始化连接池

先把连接池配置好,这是复用连接的基础:

import tormysql
from tornado import ioloop
from tornado.gen import coroutine

# 初始化连接池,根据你的数据库信息修改参数
db_pool = tormysql.ConnectionPool(
    max_connections=20,  # 最大连接数
    idle_seconds=300,    # 连接闲置超时
    wait_connection_timeout=3,  # 获取连接超时时间
    host="localhost",
    user="your_username",
    passwd="your_password",
    db="your_database",
    charset="utf8mb4"
)

第二步:写正确的异步插入函数

这里分两种写法,对应不同版本的Tornado:

写法1:用@coroutine装饰器(兼容旧版Tornado)

@coroutine
def insert_to_db(url):
    conn = None
    try:
        # 从连接池异步获取连接,必须用yield等待
        conn = yield db_pool.Connection()
        with conn.cursor() as cursor:
            # 异步执行插入SQL,同样需要yield
            sql = "INSERT INTO urls (url) VALUES (%s)"
            yield cursor.execute(sql, (url,))
            # 异步提交事务
            yield conn.commit()
        print(f"成功插入URL: {url}")
    except Exception as e:
        print(f"插入失败: {url}, 错误: {str(e)}")
        # 出错回滚事务
        if conn:
            yield conn.rollback()
    finally:
        # 释放连接回池,必须做
        if conn:
            conn.close()

写法2:用async/await(Tornado 5.0+推荐)

async def insert_to_db(url):
    conn = None
    try:
        conn = await db_pool.Connection()
        async with conn.cursor() as cursor:
            sql = "INSERT INTO urls (url) VALUES (%s)"
            await cursor.execute(sql, (url,))
            await conn.commit()
        print(f"成功插入URL: {url}")
    except Exception as e:
        print(f"插入失败: {url}, 错误: {str(e)}")
        if conn:
            await conn.rollback()
    finally:
        if conn:
            conn.close()

第三步:确保协程被调度执行

这是你最可能忽略的点!如果只是直接调用insert_to_db("http://xxx.com"),函数根本不会执行——你需要把它放到Tornado的IO循环里调度:

场景1:批量爬取URL后插入

如果是批量处理URL列表,写一个入口协程,然后用run_sync启动:

@coroutine
def batch_process(url_list):
    # 遍历URL,逐个异步插入(也可以用gen.multi并发插入,效率更高)
    for url in url_list:
        # 必须用yield等待插入完成,或者用gen.multi并发
        yield insert_to_db(url)

# 启动IO循环执行协程
if __name__ == "__main__":
    # 假设这是你爬取到的URL列表
    crawled_urls = [
        "http://example.com",
        "http://test.com",
        "http://sample.com"
    ]
    ioloop.IOLoop.current().run_sync(lambda: batch_process(crawled_urls))

场景2:爬取到URL就立即插入(比如异步爬虫中)

如果是用Tornado的异步HTTP客户端爬取,在回调协程里直接yield或await插入函数即可:

@coroutine
def crawl_single_url(url):
    # 模拟异步爬取逻辑
    from tornado.httpclient import AsyncHTTPClient
    client = AsyncHTTPClient()
    response = yield client.fetch(url)
    # 爬取完成后立即异步插入
    yield insert_to_db(url)

关键误区提醒

  1. 不要直接调用协程函数:insert_to_db(url)只会返回一个协程对象,必须用yield/await或者交给IOLoop调度才会执行。
  2. 所有异步操作都要等待:获取连接、执行SQL、提交/回滚,这些步骤都是异步IO,必须用yield/await等待完成,否则会跳过操作直接执行后续代码。
  3. 必须释放连接:不管插入成功还是失败,都要把连接放回池里,否则会导致连接耗尽。

内容的提问来源于stack exchange,提问作者Daniel Paczuski Bak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:45:10