Подтвердить что ты не робот

.net для цикла while с тайм-аутом

Я обычно использую цикл while, который продолжает выполнять некоторую операцию до тех пор, пока операция не завершится или не истечет время ожидания:

bool success = false
int elapsed = 0
while( ( !success ) && ( elapsed < 10000 ) )
{
     Thread.sleep( 1000 );
     elapsed += 1000;
     success = ... some operation ...     
}

Я знаю, что есть несколько способов реализовать это, но основная мысль заключается в том, что я несколько раз пытаюсь выполнить операцию со сном до успеха или я слишком долго спал в совокупности.

Есть ли встроенный .net класс/метод/etc, чтобы избавить меня от повторной записи этого шаблона повсюду? Возможно, ввод - это Func (от bool) и тайм-аут?

Изменить
Спасибо всем, кто внес свой вклад. Я выбрал метод sleep(), потому что он был наименее сложным, и я полностью против сложности =) Здесь моя (все еще нужно протестировать) implimentation:

 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;
    }
4b9b3361

Ответ 1

Вы можете обернуть свой алгоритм в методе:

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
}

Ответ 2

Я не знаю, что есть какая-то существующая вещь, но я бы подумал, что вы можете создать метод, который будет принимать тайм-аут и функцию определения успеха. Что-то вроде этого:

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;
}

Ответ 3

Вам действительно не нужно использовать Sleep(), чтобы ждать завершения задач. Вы тратите в среднем 500 мс после завершения задачи, выполняя это.

Вы должны сделать это детерминистически, используя параллельную библиотеку задач, например, здесь.

В этом примере показано, как использовать Wait метод или его эквивалент в Класс задачи, чтобы ждать на единственная задача. Он также показывает, как использовать статические методы WaitAll и WaitAny для ожидания нескольких задач.

Ответ 5

Другие упомянули технологии синхронизации потоков, которые позволят вам подождать, пока не будет завершена какая-либо задача. Однако, если вы хотите продолжать опрос каждую секунду, как вы делаете, вы можете обернуть этот метод следующим образом:

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.");
}

Ответ 6

Вы можете абстрагироваться от сокращения кода и обобщить Timeout:

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;
}

Ответ 7

Вам нужно использовать Thread.Join. Из MSDN,

Блокирует вызывающий поток до тех пор, пока поток заканчивается, продолжая выполнять стандартные COM и SendMessage накачка.

Если вы хотите подождать до истечения заданного времени, используйте метод Thread.Join(TimeSpan). Только .NET 3.0, 3.5, 4.0.

Блокирует вызывающий поток до тех пор, пока нить завершается или указано время истекает, продолжая выполнять стандартные COM и SendMessage накачка.

Этот учебник по использованию Темы в С# помогут вам.