C# asp.net内核中的队列任务
例如,在功能方面,有20个用户,他们几乎一次点击了发送按钮,所以方法堆叠在队列中,发送第一条用户消息,接收第二条第三条之后的响应,依此类推。用户不会与其他人聊天,而是使用响应非常快的设备进行聊天C# asp.net内核中的队列任务,c#,asp.net,asp.net-core,queue,semaphore,C#,Asp.net,Asp.net Core,Queue,Semaphore,例如,在功能方面,有20个用户,他们几乎一次点击了发送按钮,所以方法堆叠在队列中,发送第一条用户消息,接收第二条第三条之后的响应,依此类推。用户不会与其他人聊天,而是使用响应非常快的设备进行聊天 因此,我尝试将发送消息的任务排队。 我找到了使用任务队列的代码示例,如示例1和示例2所示。 示例1 public class SerialQueue { readonly object _locker = new object(); WeakReference<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;
}
}
}
公共类串行队列
{
只读对象_locker=新对象();
WeakReference\u lastTask;
公共任务排队(操作)
{
返回排队(()=>{
动作();
返回null;
});
}
公共任务排队(Func函数)
{
锁(储物柜)
{
Task lastTask=null;
任务结果任务=null;
if(_lastTask!=null&&u lastTask.TryGetTarget(out lastTask))
{
resultTask=lastTask.ContinueWith(=>function());
}
其他的
{
resultTask=Task.Run(函数);
}
_lastTask=新的WeakReference(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();
}
}
}
公共类任务队列
{
私有只读信号量limu信号量lim;
公共任务队列()
{
_semaphoreSlim=新的semaphoreSlim(1);
}
公共异步任务排队(Func taskGenerator)
{
wait_semaphoreSlim.WaitAsync();
尝试
{
返回等待任务生成器();
}
最后
{
_semaphoreSlim.Release();
}
}
公共异步任务排队(Func taskGenerator)
{
wait_semaphoreSlim.WaitAsync();
尝试
{
等待任务生成器();
}
最后
{
_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();
}
[HttpPost(Name=“添加消息”)]
公共异步任务PostMessage([FromBody]Messenger视图模型Messenger视图模型)
{
TaskQueue TaskQueue=新建TaskQueue();
SerialQueue SerialQueue=新的SerialQueue();
等待taskQueue.Enqueue(()=>SendMessage(Messenger ViewModel.PhoneNr、Messenger ViewModel.MessageBody、,
messengerViewModel.ContactId,messengerViewModel.State));
//我不会同时运行任务,一次使用一个或另一个
等待serialQueue.Enqueue(()=>SendMessage(Messenger ViewModel.PhoneNr、Messenger ViewModel.MessageBody、,
messengerViewModel.ContactId,messengerViewModel.State));
返回Ok();
}
如何解决问题并通过每次单击将任务堆叠到队列中?您的问题是每次都创建一个新的
TaskQueue
和SerialQueue
。因此,每次用户单击/调用PostMessage
时,都会创建一个新队列,该任务是队列中的第一个任务,并直接执行
您应该使用静态/单例队列,以便每次单击/调用都在同一队列对象上工作
但当你在多台服务器上扩展你的webapp时,这会带来问题。为此,您应该(例如)将Azure队列存储与Azure函数结合使用
Startup.cs
public void配置服务(IServiceCollection服务)
{
services.AddSingleton();
services.AddSingleton();
//其余的
}
SomeController.cs
[HttpPost(Name=“添加消息”)]
公共异步任务后消息(
[FromBody]Messenger视图模型Messenger视图模型,
[FromServices]任务队列任务队列,
[FromServices]串行队列(串行队列)
{
等待任务队列。排队(
()=>发送消息(
Messenger ViewModel.PhoneNr,
Messenger ViewModel.MessageBody,
Messenger ViewModel.ContactId,
信使视图模型(State));
//我不会同时运行任务,一次使用一个或另一个
等待串行队列。排队(
()=>发送消息(
Messenger ViewModel.PhoneNr,
Messenger ViewModel.MessageBody,
Messenger ViewModel.ContactId,
信使视图模型(State));
返回Ok();
}
感谢您的回复,此程序将托管在本地服务器上,因此我不知道连接多台服务器是否会出现问题。如果我理解正确,我需要将队列作为singleton注入Startup.cs?正确,然后使用DI获取队列。这样,您总是使用相同的对象services.AddSingleton()代码>以这种方式注入队列,但仍然发生相同的情况,或者我遗漏了一些重要的内容?添加了如何在控制器中使用它的示例
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();
}