也许有一些现成的代码,以免重新发明轮子。
场景是这样的。该代码生成一些更新,然后通过某种方法进行处理。更新可能生成得太频繁,加上处理方法可能会变慢,结果更新没有时间被处理,它们会累积起来,然后处理器会做不必要的工作。我想在处理程序忙碌时以某种方式“累积”更新。而且,更新数据本身就已经在“累积”了,你不需要担心这个,你只需要把请求的“累积”解析到handler上,这样handler空闲的时候就不会处理所有的了单独累积的更新请求,但立即处理整个“更新”包。
像现在:
async Task UpdateFoo()
{
...
await SaveAsync();
}
async Task UpdateBar()
{
...
await SaveAsync();
}
async Task UpdateBaz()
{
...
await SaveAsync();
}
async Task SaveAsync()
{
// здесь нужно сделать так,
// чтобы одновременно обрабатывался только один запрос
// по окончании которого проверялось бы не было ли ещё запросов
// и если были, то обновление запускалось бы ещё один раз (сразу за всё "накопленное")
// и так пока есть обновления по окончании очередной обработки
}
当然逻辑应该比较简单,脚本也应该很典型,但我不知道如何正常编写。为了登录一次 - 很明显SemaphoreSlim(带有WaitAsync)。但是完成剩下的事情最好的方法是什么?
让我们举一个一般性的例子
System.Threading.Channels.Channel<T>。编写一个 raking 方法
让我们启动工人
把它扔进运河里
要(永久)关闭通道并使该方法
WorkerAsync完成,您需要调用这就是全部的魔力。
这是基于您自己回答的代码,逻辑完全相同
在这里,您只能在应用程序的整个持续时间内启动消费者一次,如何停止它如上所示 -
_channel.Writer.Complete()这个任务的意义在于,如果你的应用程序结束了,你可以例如调用它
Complete()并await task;等待直到所有请求都被worker处理完,然后正常关闭。但您提出的解决方案并没有提供这种可能性。如果所有 SaveAsync 调用都来自一个线程,那么您可以这样实现:
将更改排队
如果保护工作已经在进行中,请等待其完成
如果队列不为空
否则
如果调用可以是多线程的,那么您在放置锁时需要非常小心,以便它们覆盖所有操作,但不包括等待时间。
像这样的东西(但我不保证任何事情,一般来说,我就写在这里):
但如果这里还需要添加错误处理的话,那你还真需要考虑很久了……
到目前为止,我已经使用一个任务和两个信号量自己完成了,尽管其他解决方案也很有趣,但不太适合我的任务。关键是一个更新正在工作,另一个更新正在队列中等待,所有其他更新都被丢弃 - 它们是不必要的,第二个挂起的更新就足够了。
请大家批评指正。)