我想問一個我想到的問題。這個關于記憶體訪問的問題,包含在asp.net核心中具有單例生命周期的物件。所以,假設這個結構中存在兩個執行緒。其中之一是asp net中使用的普通請求/回應執行緒。另一個執行緒在后臺持續運行作業服務。
我的計劃是創建任務佇列。在佇列中,我存盤了不想在請求/回應執行緒中執行的任務。這個存盤的函式在后臺連續執行。
此代碼磁區包含到任務佇列。所以這個類在后臺作業服務和 asp.net 中的任何地方使用。
public class EventQueue : IEventQueue
{
public LinkedList<Task> Queue = new LinkedList<Task>();
public void AddEvent(Task task)
{
Queue.AddFirst(task);
}
public Task GetNextEvent()
{
var task = Queue.Last.Value;
Queue.RemoveLast();
return task;
}
}
此代碼磁區包含到作業程式服務。它在佇列任務中一一執行
public class QueueWorker : BackgroundService
{
private readonly IEventQueue _queue;
public QueueWorker(IEventQueue queue)
{
_queue = queue;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var task = _queue.GetNextEvent();
if (task != null)
task.RunSynchronously();
}
}
}
此代碼磁區包含已注冊的服務。
services.AddSingleton<IEventQueue,EventQueue>();
services.AddHostedService<QueueWorker>();
問題:
- Does this structure work well? I think, It's will not work well bcs there is multiple access to queue instance. Or rather worker service is always accessing to queue instance. Therefore there will be no time to access for other threads. So this approach's right?
- if singleton lifetime wasn't used and EventQueue was static(at least LinkedList property was static), Would things be different?
- Do you have any suggestions for the improvement of this structure?
uj5u.com熱心網友回復:
對于此類任務,我建議查看ConcurrentQueue集合。
這應該提供一個不需要任何鎖的執行緒安全集合。或者,如果您不能使用上述佇列,您可以使用 SemaphoreSlim 物件作為鎖。
據我所知,使用 ConcurrentQueue 應該洗掉您提到的訪問塊。如果您使用 SemaphoreSlim,那么我會建議在后臺服務回圈中使用一個小的 Task.Delay()。
至于改進,你總是可以嘗試改造這個服務以利用事件,所以當有東西加入佇列時,后臺服務將開始處理,直到沒有任何東西剩下。
uj5u.com熱心網友回復:
我會建議不要在帶有作業人員后臺的單獨佇列執行緒上處理任務。
相反,請考慮使用異步任務,.net 非常擅長推送資料,因為每個任務都有自己的執行緒,無論如何這種結構足以釋放您的回應執行緒:
[HttpGet("")]
public async Task<IActionResult> Get(){
return await Task<IActionResult>.Factory.StartNew(() => {
//TODO: Your lengthy task here
});
}
現在說你想要一個工人型別的物件,它必須是一個單例嗎?我想不是,但不管它可以注入,但是單例必須處理并發請求,它們確實需要考慮使用。
private readonly IWorkerInterface _worker;
public ControllerConstructor(IWorkerInterface worker){
//Assign variable to controller variable
_worker = worker ?? throw new ArgumentNullException(nameof(worker));
}
[HttpGet("")]
public async Task<IActionResult> Get(){
return await Task<IActionResult>.Factory.StartNew(() => {
//TODO: Your lengthy task here
_worker.DoWork();
});
}
使用異步等待模式獲得的是,一旦從工廠創建任務并創建等待句柄,執行緒就會被釋放以提供服務,這真的很快,只有在任務完成后才再次需要。
如果您想要執行緒安全佇列,請考慮使用 ConcurrentQueue
后臺作業者的問題,正如我所看到的,它不是執行緒池,除非它需要它,并且執行緒池已經通過 task.factory 供您使用
畢竟,如果我們真的想要一個佇列而不預先處理我們的作業,我們是否不希望它持久化,以便一旦控制器接受請求,它就不會在服務器崩潰時丟失?那么您需要考慮另一種技術,而不是與網路服務器一起生存和消亡的技術。
現在,您可以讓您的網路服務器在持久服務總線上發布一個主題,該主題由您的后臺作業人員訂閱,只有在處理實際成功時才能完成……我認為您的想法是這樣的,但我擔心嘗試將其構建到網路服務器的 RAM 存盤中最終會讓您頭疼。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/317060.html
標籤:c# asp.net .net multithreading memory-management
