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

C# 定时创建Task前如何校验指定参数的MyProcedure任务是否已存在

C# 同参数运行中Task去重实现方案

实现思路

使用线程安全的ConcurrentDictionary存储参数和对应运行中Task的映射关系,每次定时器触发时先校验当前参数是否已在字典中:

  • 不存在则将参数加入字典,创建并启动对应任务,任务执行结束(含异常退出)后从字典移除该参数记录
  • 已存在则直接跳过本次创建操作

实现代码

首先定义全局的跟踪字典,键的类型可根据你的myParameter实际类型调整:

// 线程安全字典,key为MyProcedure的入参myParameter,value为对应运行中的Task实例
private readonly ConcurrentDictionary<object, Task> _runningTaskMap = new ConcurrentDictionary<object, Task>();

定时器触发时的业务逻辑:

object currentParam = myParameter;

// 尝试添加参数到字典,返回false说明同参数任务正在运行,直接跳过
if (_runningTaskMap.TryAdd(currentParam, null))
{
    try
    {
        // 创建并启动任务,Task.Run为C#推荐的线程池任务启动方式
        Task execTask = Task.Run(() =>
        {
            try
            {
                MyProcedure(currentParam);
            }
            finally
            {
                // 任务无论执行成功还是抛出异常,都要移除字典中的记录
                _runningTaskMap.TryRemove(currentParam, out _);
            }
        });
        // 更新字典中存储的任务实例
        _runningTaskMap[currentParam] = execTask;
    }
    catch
    {
        // 任务启动异常时清理字典记录,避免后续同参数任务永远无法创建
        _runningTaskMap.TryRemove(currentParam, out _);
        throw;
    }
}

注意事项

  • 如果myParameter是自定义类型,需要正确重写Equals和GetHashCode方法,保证相同业务含义的参数会被判定为同一个键
  • 如果你需要等待已有任务执行完成,可在TryAdd返回false时,通过_runningTaskMap.TryGetValue(currentParam, out var existTask)拿到已有任务实例,再调用await existTask或existTask.Wait()实现等待逻辑,定时器场景下一般不需要阻塞当前线程,跳过本次执行即可
  • 不推荐直接使用new Task().Start()的方式启动任务,Task.Run会直接从线程池调度线程执行,性能和可靠性更高

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 00:15:04