asp.net 核心中的排队任务

Queuing tasks in asp.net core

例如功能 有 20 个用户,他们几乎一次单击发送按钮,因此方法堆叠在队列中,发送第一个用户消息并接收响应,然后是第二个三分之一,依此类推。用户不会与其他人聊天,但使用响应速度非常快的设备
所以我正在尝试对发送消息的任务进行排队。
我找到了使用任务队列的代码示例,如 示例 1示例 2 中所示。

示例 1

public class SerialQueue
{
    readonly object _locker = new object();
    WeakReference<Task> _lastTask;

    public Task Enqueue(Action action)
    {
        return Enqueue<object>(() => {
            action();
            return null;
        });
    }

    public Task<T> Enqueue<T>(Func<T> function)
    {
        lock (_locker)
        {
            Task lastTask = null;
            Task<T> resultTask = null;

            if (_lastTask != null && _lastTask.TryGetTarget(out lastTask))
            {
                resultTask = lastTask.ContinueWith(_ => function());
            }
            else
            {
                resultTask = Task.Run(function);
            }

            _lastTask = new WeakReference<Task>(resultTask);
            return resultTask;
        }
    }
}


示例 2

 public class TaskQueue
{
    private readonly SemaphoreSlim _semaphoreSlim;

    public TaskQueue()
    {
        _semaphoreSlim = new SemaphoreSlim(1);
    }

    public async Task<T> Enqueue<T>(Func<Task<T>> taskGenerator)
    {
        await _semaphoreSlim.WaitAsync();

        try
        {
            return await taskGenerator();
        }
        finally
        {
            _semaphoreSlim.Release();
        }
    }

    public async Task Enqueue(Func<Task> taskGenerator)
    {
        await _semaphoreSlim.WaitAsync();
        try
        {
            await taskGenerator();
        }
        finally
        {
            _semaphoreSlim.Release();
        }
    }
}


问题是,当我每次按下按钮传递我想要排队的任务时(示例 3),任务仍然同时执行并相互中断。

示例 3

 [HttpPost(Name = "add-message")]
        public async Task<IActionResult> PostMessage([FromBody] MessengerViewModel messengerViewModel)
        {
            TaskQueue taskQueue = new TaskQueue();
            SerialQueue serialQueue = new SerialQueue();

            await taskQueue.Enqueue(() => SendMessage(messengerViewModel.PhoneNr, messengerViewModel.MessageBody,
                messengerViewModel.ContactId, messengerViewModel.State));
//I'm not running tasks at same time, using one or other at time
            await serialQueue.Enqueue(() => SendMessage(messengerViewModel.PhoneNr, messengerViewModel.MessageBody,
                messengerViewModel.ContactId, messengerViewModel.State));

            return Ok();
        }

如何通过每次点击解决问题并将任务堆叠到队列中?

您的问题是您每次都创建一个新的 TaskQueueSerialQueue。这样每次用户clicks/invokesPostMessage都会创建一个新的队列,任务是队列中的第一个任务,直接执行。

您应该使用 static/singleton 队列,这样每个 click/invoke 都在同一个队列对象上工作。

但是当您跨多个服务器扩展您的 web 应用程序时,这会带来问题。为此,您应该将(例如)Azure 队列存储与 Azure Functions 结合使用。


Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<TaskQueue>();
    services.AddSingleton<SerialQueue>();
    // the rest
}

SomeController.cs

[HttpPost(Name = "add-message")]
public async Task<IActionResult> PostMessage(
    [FromBody] MessengerViewModel messengerViewModel,
    [FromServices] TaskQueue taskQueue,
    [FromServices] SerialQueue serialQueue)
{
    await taskQueue.Enqueue(
        () => SendMessage(
                  messengerViewModel.PhoneNr, 
                  messengerViewModel.MessageBody,
                  messengerViewModel.ContactId, 
                  messengerViewModel.State));
    //I'm not running tasks at same time, using one or other at time
    await serialQueue.Enqueue(
        () => SendMessage(
                  messengerViewModel.PhoneNr, 
                  messengerViewModel.MessageBody,
                  messengerViewModel.ContactId, 
                  messengerViewModel.State));

    return Ok();
}