简体   繁体   English

在asp.net核心中排队任务

[英]Queuing tasks in asp.net core

Eg of functionality There is 20 users and they clicked send button almost in one time, so methods stacking in queue and first user message is sent and response received, after second third and so on. 例如功能有20个用户,他们几乎一次点击发送按钮,因此发送队列和第一个用户消息的方法发送并收到响应,在第二个三分之后,依此类推。 Users wont chat with other people but with device which response is pretty fast 用户不会与其他人聊天,但设备响应非常快
So I am trying to queue Task which sends Message. 所以我正在尝试排队发送Message的Task。
I found code samples that uses Task queuing as shown in Example 1 and Example 2 . 我找到了使用任务队列的代码示例,如示例1示例2所示

Example 1 例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;
        }
    }
}


Example 2 例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();
        }
    }
}


Problem is that when I'm passing task which I want to queue ( Example 3 ) each time I pressing button, tasks still are executed at the same time and interrupting each other. 问题是当我每次按下按钮时都要传递我要排队的任务( 例3 )时,任务仍然会同时执行并相互中断。

Example 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();
        }

How could I solve problem and stack task to queue by each click? 如何通过每次点击解决问题和堆栈任务排队?

Your problem is that you create a new TaskQueue and SerialQueue everytime. 您的问题是每次都创建一个新的TaskQueueSerialQueue Thus each time a user clicks/invokes PostMessage a new queue is created, and the task is the first task in the queue and executed directly. 因此,每次用户单击/调用PostMessage都会创建一个新队列,该任务是队列中的第一个任务并直接执行。

You should use a static/singleton queue so each click/invoke works on the same queue object. 您应该使用静态/单例队列,以便每次单击/调用对同一队列对象起作用。

But that would deliver problems when you scale your webapp across multiple servers. 但是,当您跨多个服务器扩展Web应用程序时,这会产生问题。 To that end you should use things like (for example) Azure Queue Storage in combination with Azure Functions. 为此,您应该使用(例如)Azure Queue Storage与Azure Functions结合使用的内容。


Startup.cs Startup.cs

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

SomeController.cs 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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM