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

时间:2014-12-01 14:17:15

标签: c# asp.net signalr

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

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

1 个答案:

答案 0 :(得分:1)

BlockingCollection怎么样? 我认为在你的情况下,它提供了你正在寻找的东西: 它是一个带有

的线程安全集合
  1. Producer-Consumer模式的实现。
  2. 从多个线程同时添加和获取项目。
  3. 您可以在TaskPool类中替换

    private Dictionary<string, LongRunningJob> pool;
    

    BlockingCollection<T>元素

    查看this页面

    中的示例

    您还可以使用ConcurrentQueue类进行线程安全的先进先出(FIFO)集合