执行长时间运行的作业的任务的 SignalR 池

本文关键字:任务 SignalR 作业 执行 长时间 运行 执行长 | 更新日期: 2023-09-27 18:32:34

我在应用程序中有一个 SignalR 中心 ASP.Net 可以启动不同的任务

public async Task StartHeatingTask()
{
    await TaskPool.Instance.TryRun<Heating>(identifier, Heating_ReportProgress);
}
...
void Heating_ReportProgress(TaskProgressStatus status, OperationProgressEventArgs[] args)
{
    this.Clients.All.reportProgress(status, args);
}

我的问题是如何避免重复执行同一任务(标识符相同)。这是我当前的TaskPool实现,尽管我不确定我是否正确使用了locksawait的组合:

public class TaskPool
{
    private Dictionary<string, LongRunningJob> pool;
    private object syncRoot = new object();

    public static TaskPool Instance = new TaskPool();
    public async Task TryRun<T>(string identifier, LongRunningJob.Progress progressHandler, bool captureContext = false)
            where T : LongRunningJob, new()
    {
        Task worker = null;
        if (!this.pool.ContainsKey(identifier))
        {
            lock (this.syncRoot)
            {
                if (!this.pool.ContainsKey(identifier))
                {
                    LongRunningJob job = new T {Identifier = identifier};
                    job.ProgressEventHandler += progressHandler;
                    this.pool.Add(identifier, job);
                    worker = job.RunAsync().ContinueWith(task => { this.pool.Remove(identifier); });
                }
            }
            if (worker != null)
            {
                await worker.ConfigureAwait(captureContext);
            }
        }
    }
    public bool Terminate(string identifier)
    {
        if (this.pool.ContainsKey(identifier))
        {
            lock (this.syncRoot)
            {
                if (this.pool.ContainsKey(identifier))
                {
                    this.pool[identifier].Terminate();
                    return true;
                }
            }
        }
        return false;
    }
}

我还应该await由以前的用户调用启动的相同任务。我是C# 5 Task新手,所以我的概念很可能是错误的,应该完全重新设计。

https://dotnetfiddle.net/SAeTtj

执行长时间运行的作业的任务的 SignalR 池

那么

BlockingCollection呢?我认为在您的情况下,它提供了您正在寻找的内容:它是一个线程安全的集合,具有

  1. 生产者-消费者模式的实现。
  2. 从多个线程并发添加和获取项目。

在任务池类中,您可以替换

private Dictionary<string, LongRunningJob> pool;

BlockingCollection<T>元素

查看此页面中的示例

还可以将 ConcurrentQueue 类用于线程安全的先进先出 (FIFO) 集合