Длительная операция с таймаутом


У меня есть длительная операция, что мне нужно ждать или тайм-аут. У меня есть рабочий код, но хотелось бы ваше мнение по его улучшению.

public bool RegisterEquipmentListUpdate(int ID)
{
    if (Authentication.CheckSession(Session))
    {
        var wcfmonitoring = new WCFMonitoring.MonitoringDatabaseClient();
        try
        {
            bool timeout = false;
            DateTime start = DateTime.Now;
            //loop as long as the time isn't reached (600 seconds)
            while (!timeout)
            {
                if (wcfmonitoring.CheckForEquipmentUpdate(Authentication.GetSessionID(Session), Authentication.GetPTO(Session), ID))
                {
                    wcfmonitoring.Close();
                    //sleep before returning true, this is set so the importer can finish multiple files without the client refreshing on the first one
                    Thread.Sleep(2000);
                    return true;
                }
                else
                {
                    //sleep for 10 seconds before trying again
                    Thread.Sleep(10000);
                    //if the elapsed time is more than 10 minutes return false
                    if (start < DateTime.Now.AddSeconds(-600))
                    {
                        wcfmonitoring.Close();
                        return false;
                    }
                }
            }
        }
        catch
        {
            wcfmonitoring.Abort();
        }
    }
    //return false in case of error
    return false;
}


261
2
задан 2 марта 2018 в 12:03 Источник Поделиться
Комментарии
1 ответ

Это черновой вариант, так как я не знаю общую картину вашего проекта. Некоторые дизайн может быть улучшен, чтобы даже не использовать этот код (события, семафоры, мьютексы, и другие более предсказуемые механизмы синхронизации). Я редко использую этот шаблон для кода, который я контролирую, больше за код я не могу, что я знаю, блокирует. Такой подход является рискованным, так как это может привести к нежелательным состоянием и потери данных. Вы были предупреждены! (http://thedailywtf.com/articles/My-Tales) для справки!)

Если вы остановитесь на этом пути, я рекомендую быть отдельный класс/метод, отвечающий за такое поведение, в пользу повторного использования, это также включает в себя возможность пройдя CancellationToken, просто на случай, если вы передумаете о запросе:

public async Task<T> WaitForActionCompletionOrTimeout<T>(Func<T> action, int timeout, CancellationToken? globalCancellation = null)
{
var result = default(T); //return default for error

var localCancellation = new CancellationTokenSource();
var localAndGlobalCancellation =
CancellationTokenSource.CreateLinkedTokenSource(localCancellation.Token,
globalCancellation.HasValue ?
globalCancellation.Value :
CancellationToken.None);

Task cancelationTask = null;
Task actionTask = null;

try
{
cancelationTask = Task.Delay(timeout, localAndGlobalCancellation);
actionTask = Task.Factory.StartNew(() =>
{
result = action.Invoke();
}, localAndGlobalCancellation);
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
localCancellation.Cancel();
return null;
}

await Task.WhenAny(actionTask, cancelationTask).ContinueWith(t => localCancellation.Cancel());
return result;
}

Изменить метод работы, чтобы возвратить true или false, что-то вроде:

public bool CheckForUpdate()
{
using (var wcfmonitoring = new WCFMonitoring.MonitoringDatabaseClient())
{
var sw = new SpinWait();
while (!wcfmonitoring.CheckForEquipmentUpdate(Authentication.GetSessionID(Session), Authentication.GetPTO(Session), ID)) //maybe something shorter would work :) some variables are nice for debugging
{
sw.SpinOnce(); //magic Thread.Sleep(5) replacement with lots of goodies :) nice class to look at
}

Thread.Sleep(2000); //for the importer
return true;
}
}

А затем:

var success = WaitForActionCompletionOrTimeout(() => CheckForUpdate, 600000 ); //I would so like 6.minutes.in.miliseconds.... ah dreams

Такого рода подход (отмена работником) также может быть выполнена с резьбой в гораздо более короткие и грубой forcier пути для медленного увеличения производительности в случае очень низкого времени ожидания.

Я бы также посоветовал использовать используя и если WcfMonitoring не интерфейс IDisposable, чтобы сделать его интерфейс IDisposable.

Еще один вопрос: Какова цель/разница между вызов abort и объектов в коде?

1
ответ дан 3 марта 2018 в 05:03 Источник Поделиться