我通常使用while循环继续尝试某些操作,直到操作成功或超时为止:
bool success = false
int elapsed = 0
while( ( !success ) && ( elapsed < 10000 ) )
{
Thread.sleep( 1000 );
elapsed += 1000;
success = ... some operation ...
}
我知道有几种方法可以实现这一点,但基本的一点是我反复尝试一些操作,一直睡到成功,或者我已经睡了太长时间。
是否有内置的.net类/方法/等来阻止我在整个地方重写这个模式?也许输入是一个Func(bool)和超时?
编辑
感谢所有贡献者。我选择了sleep()方法,因为它是最不复杂的,我完全反复杂性=)这是我的(仍然需要测试)实现:
public static bool RetryUntilSuccessOrTimeout( Func<bool> task , TimeSpan timeout , TimeSpan pause )
{
if ( pause.TotalMilliseconds < 0 )
{
throw new ArgumentException( "pause must be >= 0 milliseconds" );
}
var stopwatch = Stopwatch.StartNew();
do
{
if ( task() ) { return true; }
Thread.Sleep( ( int )pause.TotalMilliseconds );
}
while ( stopwatch.Elapsed < timeout );
return false;
}
答案 0 :(得分:21)
您可以将算法包装在一个方法中:
public bool RetryUntilSuccessOrTimeout(Func<bool> task, TimeSpan timeSpan)
{
bool success = false;
int elapsed = 0;
while ((!success) && (elapsed < timeSpan.TotalMilliseconds))
{
Thread.Sleep(1000);
elapsed += 1000;
success = task();
}
return success;
}
然后:
if (RetryUntilSuccessOrTimeout(() => SomeTask(arg1, arg2), TimeSpan.FromSeconds(10)))
{
// the task succeeded
}
答案 1 :(得分:12)
您可以使用SpinWait.SpinUntil
请参阅https://msdn.microsoft.com/en-us/library/dd449238(v=vs.110).aspx
bool spinUntil = System.Threading.SpinWait.SpinUntil(() => job.IsDisposed, TimeSpan.FromSeconds(5));
答案 2 :(得分:5)
您真的不应该使用Sleep()
等待任务完成。完成任务后,您平均浪费500毫秒。
您应该能够使用任务并行库确定性地执行此操作,例如,请参阅here。
此示例显示如何使用Wait 方法,或其中的等价物 任务类,等待 单一任务。它还显示了如何使用 静态WaitAll和WaitAny方法 等待多项任务。
答案 3 :(得分:4)
我不知道有任何现有的东西,但我认为你可以创建一个接受超时和成功决定功能的方法。像这样:
public static bool KeepTrying(int timeout, Func<bool> operation)
{
bool success = false;
int elapsed = 0;
while ((!success) && (elapsed < timeout))
{
Thread.Sleep(1000);
elapsed += 1000;
success = operation();
}
return success;
}
或者你的函数可能更“强大”,你可以将它与灵活的参数结合起来:
public bool KeepTrying(int timeout, Func<object[], bool> operation, params object[] arguments)
{
bool success = false;
int elapsed = 0;
while ((!success) && (elapsed < timeout))
{
Thread.Sleep(1000);
elapsed += 1000;
success = operation(arguments);
}
return success;
}
答案 4 :(得分:2)
其他人已经提到了线程同步技术,这将允许您等到某个任务完成。但是,如果你想像你一样继续轮询每一秒,你可以像这样包装那个方法:
void Main()
{
Timeout(() => {return false;});
}
public void Timeout(Func<bool> action, int timeout)
{
bool success = false;
int elapsed = 0;
while( ( !success ) && ( elapsed < timeout ) )
{
Thread.Sleep( 1000 );
elapsed += 1000;
success = action();
}
Console.WriteLine("timed out.");
}
答案 5 :(得分:1)
您可以抽象缩短代码并概括超时:
int timer = 0;
while (!SomeOperation(...) && Timeout(ref timer, 1000, 10000));
public bool Timeout(ref int timer, int increment, int maximum)
{
timer += increment;
Thread.Sleep(increment);
return timer < maximum;
}
答案 6 :(得分:1)
第一种解决方案是使用SpinWait
SpinWait.SpinUntil(() => LoopProcedure(), 1000);
另一种解决方案是使用Task.Wait()
var task = Task.Run(() => LoopProcedure());
task.Wait(1000);
将循环包装到返回bool值的过程
private bool LoopProcedure()
{
bool success = false
while( ( !success )
{
// do some stuff ...
}
return success;
}
答案 7 :(得分:0)
您需要使用Thread.Join。来自MSDN,
阻止调用线程直到a 线程终止,同时继续 执行标准COM和SendMessage 泵送。
如果要等到指定的时间过去,请使用Thread.Join (TimeSpan)方法。仅限.NET 3.0,3.5,4.0。
阻止调用线程直到a 线程终止或指定 时间流逝,同时继续 执行标准COM和SendMessage 泵送。
本教程如何使用Threads in C#对您有帮助。
答案 8 :(得分:0)
我更喜欢异步任务方法。复制了很多东西,但是我的测试版本是:
async Task<bool> DelayTillCondition(Func<bool> exitCondition, int delayInMs, int timeoutInSec)
{
bool success = false;
int elapsed = 0;
while ((!success) && (elapsed < timeoutInSec * 1000))
{
await Task.Delay(delayInMs);
elapsed += delayInMs;
success = exitCondition();
}
return success;
}
和紧凑的单行方法调用:
await DelayTillCondition(() => status == "Connected", 500, 30);
请考虑此处未捕获到int参数超限!