【发布时间】:2019-11-12 14:35:59
【问题描述】:
我正在重构使用Thread.Sleep 的代码,并且在出现错误时重试SQL 查询的时间限制越来越长。用于阻塞的Thread.Sleep 的常见替代品似乎是await Task.Delay,这需要将方法更改为async。该方法现在看起来像这样(为简洁起见,删除了额外的错误检查):
private static async Task<int> PrepareForRetry( int retryCount, SqlCommand command, int timeout )
{
++retryCount;
if (retryCount < ConnectionRetryCount)
{
int SleepTime = _connectionRetryBackoffTimes[retryCount - 1] + (_connectionRetryRandomBackoff.Next() % 500);
//Thread.Sleep(SleepTime);
await Task.Delay(SleepTime);
}
return retryCount;
}
我遇到的问题是async 要求调用方法为async,依此类推。尽管最终重构为完全异步,但这远远超出了当前的重构范围。
我遇到的问题是如何从同步代码中调用方法并获取结果。使用
retryCount = PrepareForRetry(retryCount, command, timeout).Result;
创建死锁,因为 UI 线程正在调用该方法。我发现我可以通过将Task.Delay 更改为
await Task.Delay(SleepTime).ConfigureAwait(false);
但我不完全明白这是做什么的。我也尝试过使用
调用该方法retryCount = Task.Run(async () => { await PrepareForRetry(retryCount, command, timeout).Result; });
但这有错误“'int'不包含'GetAwaiter'的定义”,我无法找出如何继续获得结果。使用 Task.Delay 是否是创建延迟的正确方法(计时器不允许增加等待时间),如果是,我应该如何调用该方法来获取返回值?
【问题讨论】:
-
旁注:你为什么这样做?除非你全力以赴,让一切都正确异步,否则本地 UI 应用程序没有任何好处(请参阅stackoverflow.com/questions/20082221/…,根据你的实际目标,它甚至可能重复)。旁注 2:我将从顶部而不是底部开始转换 - 可以从
async调用同步方法,但实际上不是相反。 -
从顶部开始转换,而不是从底部开始 - +1
-
经验法则是,如果您需要在
async方法上调用.Result,或者您要将其卸载到带有Task.Run的新 线程,那么您会更很可能做错了什么,简而言之,使用Thread.Sleep,除非你想将整个调用堆栈传播到async -
我不明白延迟的必要性。您是否正在尝试处理数据库连接的超时问题?有更好的方法来处理。
-
@JohnWu - 我很想以正确的方式处理这个问题。这是我们 DAL 的根,显然如果数据库访问失败,我们的程序将无法工作。我正在尝试找到处理 SqlException 的正确方法,以最大可能地检索或保存数据,但不知道从哪里开始。你能推荐一个文章或模式名称吗?
标签: c# asynchronous async-await task