c# - 在无限循环中执行 await Task.Delay
问题描述
我有下面的代码,它将执行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
内部调用,所以这是一个很好的近似值)。
推荐阅读
- c# - 如何在 Blazor 中保留组件实例
- mapbox - 将 Mapbox 样式复制到另一个帐户,其中包含它使用的图块集
- node.js - 使两个不同的应用程序一起工作的最佳方法是什么?(React.js 和 JSP)
- python - Python3如何从一列分配一个序数值并基于另一列创建多行
- python - Ctype - 找不到 DLL 依赖项
- linux - awk, sed, grep Linux 文件中的特定字符串
- python - 当 Firebase 云消息传递 API 失败时重试
- php - 日历表 PHP
- php - 如何将完整 URL 作为端点添加到 GET 请求
- php - 如何从价格计算中显示总计