例如功能的实现有20个用户,他们几乎一次单击了发送按钮,因此在队列中堆叠的方法和发送第一个用户消息并接收响应的方法,在第二个,第三个之后等等。用户不会与其他人聊天,但会使用响应速度非常快的设备
所以我试图将发送消息的Task排队。
我发现了使用任务排队的代码示例,如示例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();
}
我该如何解决问题并将堆栈任务按每次单击排队?
答案 0 :(得分:3)
您的问题是您每次都创建一个新的TaskQueue
和SerialQueue
。因此,每次用户单击/调用PostMessage
时都会创建一个新队列,该任务是队列中的第一个任务并直接执行。
您应该使用静态/单个队列,以便每次单击/调用都可在同一队列对象上进行。
但是,当您跨多个服务器扩展Web应用程序时,这会带来问题。为此,您应该结合使用Azure Queue Storage之类的东西(例如)与Azure Functions相结合。
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<TaskQueue>();
services.AddSingleton<SerialQueue>();
// the rest
}
[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();
}