我有以下代码,它将执行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);
}
}
}
答案 0 :(得分:1)
这很安全。
这是一个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;
}
当然,实际的编译代码看起来并不像这样(it looks like this),但这说明了我的观点。
这里没有递归。甚至没有无限循环。您有一个方法,该方法在被调用时会尝试执行您的操作。如果失败,则将其排队到ThreadPool上并返回。对ThreadPool.QueueUserWorkItem
的调用会立即返回,并且不会等到工作完成。
ThreadPool.QueueUserWorkItem
也不创建新线程-它将要由一个预先存在的线程池执行的工作排队。
(在有人发表评论之前-我知道实际的编译后的代码不会直接使用ThreadPool.QueueUserWorkItem
,但可能会使用默认的TaskScheduler,它在内部调用ThreadPool.UnsafeQueueUserWorkItem
,因此是一个很好的近似值)
答案 1 :(得分:0)
我认为它不会,因为一旦满足retryCount
条件,它要么通过break要么通过throw退出循环。取决于您的retryCount
会导致内存泄漏的发生方式。