[英]BackgroundService Await Task.Delay in infinite loop leaks SqlConnection objects hard
[英]Doing await Task.Delay in an infinite loop
我有下面的代碼,它將執行Action operation
,如果其中發生異常,將重試它。
因為代碼正在await Task.Delay(delay);
在while(true)
,我在猶豫這是否會導致任何內存泄漏? 喜歡創建無限threads
嗎?
這段代碼可以正常工作,但是我只擔心可能發生內存泄漏? 如果有人可以分享一些見解,我將不勝感激。
public class OperationWithBasicRetry
{
public async Task StartOperationAsync(Action operation, TimeSpan delay, int retryCount)
{
int currentRetry = 0;
while(true)
{
try
{
operation();
// Success
break;
}
catch (Exception ex)
{
if (++currentRetry > retryCount)
{
throw;
}
}
await Task.Delay(delay);
}
}
}
這很安全。
這是一個async
方法,因此編譯器將其切碎並將其變成狀態機。 作為非常粗略的近似來說明這一點,您可以認為編譯后的代碼看起來像這樣:
private class State
{
public int currentRetry;
public Action operation;
public TimeSpan delay;
public int retryCount;
public TaskCompletionSource<object> tcs;
private void StartOperationAsyncImpl(object unused)
{
try
{
operation();
tcs.SetResult(null);
return;
}
catch (Exception ex)
{
if (++currentRetry > retryCount)
{
tcs.SetException(ex);
}
}
// I'm ignoring the delay bit, because it has no affect on the point
// I'm trying to make.
ThreadPool.QueueUserWorkItem(StateOperationAsyncImpl);
}
}
public Task StartOperationAsync(Action operation, TimeSpan delay, int retryCount)
{
State state = new State();
state.currentRetry = 0;
state.operation = operation;
state.delay = delay;
state.retryCount = retryCount;
state.tcs = new TaskCompletionSource<object>();
ThreadPool.QueueUserWorkItem(state.StartOperationAsyncImpl);
return state.tcs;
}
當然,實際的已編譯代碼看起來並不像這樣( 看起來像這樣 ),但這說明了我的觀點。
這里沒有遞歸。 甚至沒有無限循環。 您有一個方法,該方法在被調用時會嘗試執行您的操作。 如果失敗,則將其排隊到ThreadPool上並返回。 對ThreadPool.QueueUserWorkItem
調用將立即返回,並且不會等到工作完成。
ThreadPool.QueueUserWorkItem
也不創建新線程-它將要由預先存在的線程池執行的工作排隊。
(在有人發表評論之前-我知道實際的編譯后的代碼不會直接使用ThreadPool.QueueUserWorkItem
,但可能會使用默認的TaskScheduler,它會在內部調用ThreadPool.UnsafeQueueUserWorkItem
,因此是一個很好的近似值)。
我認為不會,因為一旦滿足retryCount
條件,它要么通過break要么通過throw退出循環。 取決於您的retryCount
,這將導致內存泄漏。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.