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

C# 实现双方法每毫秒后台并行运行不阻塞主流程问题咨询

问题核心原因

  • 你当前用的是递归自调用实现循环,会持续占用当前线程执行,完全不会让出CPU资源给其他业务逻辑,而且还会不断累加调用栈,时间长了还会栈溢出崩溃
  • 所有数据库操作都是用的同步方法(ExecuteNonQuery、ExecuteReader),没有用对应的异步版本,即使方法标注了async Task也没有实际异步执行,会阻塞线程
  • 没有加任何时间间隔控制,两个方法会无间隔疯狂执行,不仅占满资源,还会给数据库造成极大压力,你要的1ms间隔也根本没实现
  • 调用MuteRead()和MuteUpdate()的时候没有加await,方法标注的async完全没起到作用,会直接同步阻塞执行

修复方案

第一步:改写两个方法为正确的异步实现

把同步数据库调用全部改成异步版本,加上await,同时用using自动释放数据库连接,不用手动关闭:

// 公共的连接字符串可以提出来,不用每个方法都写一遍
private const string DbConnStr = "Server=echstreme.de;Port=3306;Database=c1Look;Uid=c1Look;Pwd=Redacted;SSL Mode =None";

public async Task MuteUpdateAsync()
{
    try
    {
        using var conn = new MySqlConnection(DbConnStr);
        await conn.OpenAsync();
        using var cmd = new MySqlCommand(SQLMUteRemove, conn);
        await cmd.ExecuteNonQueryAsync();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }
}

public async Task MuteReadAsync()
{
    try
    {
        using var conn = new MySqlConnection(DbConnStr);
        await conn.OpenAsync();
        using var cmd = new MySqlCommand("SELECT * FROM `mutes` WHERE MuteUntil <= 0", conn);
        using var rdr = await cmd.ExecuteReaderAsync();
        while (await rdr.ReadAsync())
        {
            ulong id = Convert.ToUInt64(rdr[1]);
            var user = Context.Guild.GetUser(id);
            await SendLog("__Mute Manager__", $"**Member**        | <@{rdr[1]}>\n **Punishment**       | UNMUTE\n **Punished by**          | <@{rdr[4]}>");
            // 这里DELETE操作使用参数化查询,避免SQL注入
            using var deleteCmd = new MySqlCommand("DELETE FROM `mutes` WHERE `UserID` = @UserId", conn);
            deleteCmd.Parameters.AddWithValue("@UserId", rdr[1]);
            await deleteCmd.ExecuteNonQueryAsync();
            await user.RemoveRoleAsync(876561161062076416);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }
}

第二步:用后台定时任务代替递归实现间隔执行

用异步循环加延迟的方式,不会阻塞主线程,其他逻辑可以正常执行:

// 程序启动的时候调用一次这个方法启动后台任务,不要await它,让它在后台独立运行
_ = RunMuteJobsAsync();

private async Task RunMuteJobsAsync()
{
    // 可通过修改该变量控制任务启停
    while (true)
    {
        // 执行两个业务方法
        await MuteUpdateAsync();
        await MuteReadAsync();
        // 等待1ms再执行下一轮
        await Task.Delay(1);
    }
}

注:Windows系统默认定时器精度为10~15ms,即使设置Task.Delay(1),实际间隔也不会低于10ms,对于静音管理这类场景完全不需要毫秒级精度,建议把间隔调整到1秒以上,大幅降低数据库压力。

额外优化建议

  • 你原来的UPDATE逻辑是每次把MuteUntil减1,完全没必要高频跑SQL更新,可以直接在查询的时候判断MuteUntil <= UNIX_TIMESTAMP()(如果存的是Unix时间戳),直接去掉UPDATE步骤,性能会提升很多
  • 所有SQL操作都要坚持使用参数化查询,不要直接拼接用户输入的内容,避免SQL注入风险

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 13:57:03