как установить таймаут для метода - PullRequest
15 голосов
/ 11 сентября 2009

как установить тайм-аут для занятого метода + C #.

Ответы [ 8 ]

12 голосов
/ 08 октября 2009

Хорошо, вот реальный ответ.

...

void LongRunningMethod(object monitorSync)
{
   //do stuff    
   lock (monitorSync) {
     Monitor.Pulse(monitorSync);
   }
}

void ImpatientMethod() {
  Action<object> longMethod = LongRunningMethod;
  object monitorSync = new object();
  bool timedOut;
  lock (monitorSync) {
    longMethod.BeginInvoke(monitorSync, null, null);
    timedOut = !Monitor.Wait(monitorSync, TimeSpan.FromSeconds(30)); // waiting 30 secs
  }
  if (timedOut) {
    // it timed out.
  }
}

   ...

Это объединяет две самые забавные части использования C #. Во-первых, чтобы вызвать метод асинхронно, используйте делегата, который имеет причудливые штаны BeginInvoke magic.

Затем с помощью монитора отправьте сообщение с LongRunningMethod обратно на ImpatientMethod, чтобы сообщить ему, когда это будет сделано, или, если оно не получало от него сообщения в течение определенного времени, просто сдайтесь на нем.

(p.s.- Шучу, что это настоящий ответ. Я знаю, что есть 2 ^ 9303 способа убрать кошку. Особенно в .Net)

7 голосов
/ 11 сентября 2009

Вы не можете сделать это, если не измените метод.

Есть два способа:

  1. Метод построен таким образом, что он сам измеряет, как долго он работает, а затем преждевременно возвращается, если он превышает некоторый порог.
  2. Метод построен таким образом, что он отслеживает переменную / событие, которое говорит «когда эта переменная установлена, пожалуйста, выйдите», а затем у вас есть другой поток, измеряющий время, потраченное в первом методе, и затем устанавливающий, что переменная, когда истекшее время превысило некоторый порог.

Наиболее очевидный, но, к сожалению, неправильный ответ, который вы можете получить здесь: «Просто запустите метод в потоке и используйте Thread.Abort, если он слишком долго работал».

Единственно верный способ заключается в том, чтобы метод взаимодействовал таким образом, чтобы он выполнял чистый выход, если он работал слишком долго.

Существует также третий способ, когда вы выполняете метод в отдельном потоке, но после ожидания его завершения, а для этого требуется слишком много времени, вы просто говорите: «Я не собираюсь ждать его завершения» , но просто откажитесь от этого ". В этом случае метод все равно будет работать и в конечном итоге завершится, но тот другой поток, который его ожидал, просто прекратит работу.

Думайте о третьем способе, как о том, чтобы позвонить кому-нибудь и попросить его найти в их доме ту книгу, которую вы одолжили ему, и после того, как вы подождете 5 минут на своем конце телефона, вы просто скажете «ау, бросьте это» и повесьте вверх. В конце концов, этот другой человек найдет книгу и вернется к телефону, только чтобы заметить, что вы больше не заботитесь о результате.

3 голосов
/ 29 декабря 2016

Это старый вопрос, но теперь у него есть более простое решение, которое не было доступно: Задачи!

Вот пример кода:

var task = Task.Run(() => LongRunningMethod());//you can pass parameters to the method as well
if (task.Wait(TimeSpan.FromSeconds(30)))
    return task.Result; //the method returns elegantly
else
    throw new TimeoutException();//the method timed-out
3 голосов
/ 30 сентября 2013

Хотя ответ MojoFilter хороший, он может привести к утечкам, если "LongMethod" замерзнет. Вы должны прервать операцию, если вас больше не интересует результат.

public void LongMethod()
{
    //do stuff
}

public void ImpatientMethod()
{
    Action longMethod = LongMethod; //use Func if you need a return value

    ManualResetEvent mre = new ManualResetEvent(false);

    Thread actionThread = new Thread(new ThreadStart(() =>
    {
        var iar = longMethod.BeginInvoke(null, null);
        longMethod.EndInvoke(iar); //always call endinvoke
        mre.Set();
    }));

    actionThread.Start();
    mre.WaitOne(30000); // waiting 30 secs (or less)
    if (actionThread.IsAlive) actionThread.Abort();
}
2 голосов
/ 11 сентября 2009

Вы можете запустить метод в отдельном потоке, отслеживать его и принудительно завершать, если он работает слишком долго. Хороший способ, если вы можете назвать его таковым, - это разработать атрибут для метода в Post Sharp , чтобы код отслеживания не засорял ваше приложение.

Я написал следующее в качестве примера кода (обратите внимание на часть кода примера, она работает, но может иметь проблемы с многопоточностью, или если рассматриваемый метод перехватывает исключение ThreadAbortException, это нарушит его):

static void ActualMethodWrapper(Action method, Action callBackMethod)
{
    try
    {
        method.Invoke();
    } catch (ThreadAbortException)
    {
        Console.WriteLine("Method aborted early");
    } finally
    {
        callBackMethod.Invoke();
    }
}

static void CallTimedOutMethod(Action method, Action callBackMethod, int milliseconds)
{
    new Thread(new ThreadStart(() =>
    {
        Thread actionThread = new Thread(new ThreadStart(() =>
        {
            ActualMethodWrapper(method, callBackMethod);
        }));

        actionThread.Start();
        Thread.Sleep(milliseconds);
        if (actionThread.IsAlive) actionThread.Abort();
    })).Start();
}

Со следующим вызовом:

CallTimedOutMethod(() =>
{
    Console.WriteLine("In method");
    Thread.Sleep(2000);
    Console.WriteLine("Method done");
}, () =>
{
    Console.WriteLine("In CallBackMethod");
}, 1000);

Мне нужно поработать над читаемостью кода.

0 голосов
/ 09 декабря 2013

Я регулярно пишу приложения, в которых мне нужно синхронизировать критичные по времени задачи на разных платформах. Если вы можете избежать thread.abort, вы должны. См. http://blogs.msdn.com/b/ericlippert/archive/2010/02/22/should-i-specify-a-timeout.aspx и http://www.interact -sw.co.uk / iangblog / 2004/11/12 / отмены для получения инструкций о том, когда необходим thread.abort. Вот концепция, которую я реализую:

  • Выборочное выполнение: запускается только в том случае, если существует разумный шанс на успех (основанный на способности достичь тайм-аута или вероятности результата успеха относительно других элементов в очереди). Если вы разбиваете код на сегменты и знаете примерно ожидаемое время между блоками задач, вы можете предсказать, следует ли вам пропустить дальнейшую обработку. Общее время можно измерить, обернув задачи объектной корзины рекурсивной функцией для расчета времени или с помощью класса контроллера, который наблюдает за тем, как рабочие знают ожидаемое время ожидания.
  • Избирательное сиротство: ждать возвращения можно только в том случае, если существует разумный шанс на успех. Индексированные задачи выполняются в управляемой очереди. Задачи, которые превышают свое время ожидания или вызывают риск других таймаутов, становятся сиротами, и вместо них возвращается пустая запись. Более длительные задачи могут быть заключены в асинхронные вызовы. Смотрите пример оболочки асинхронных вызовов: http://www.vbusers.com/codecsharp/codeget.asp?ThreadID=67&PostID=1
  • Условный выбор: аналогично выборочному выполнению, но основан на группе, а не на отдельной задаче. Если многие из ваших задач связаны между собой так, что один успех или сбой делает дополнительную обработку неактуальной, создайте флаг, который проверяется перед началом выполнения и еще раз перед началом длительных подзадач. Это особенно полезно, когда вы используете Parallel.for или другие подобные параллельные задачи в очереди.
0 голосов
/ 11 сентября 2009

Не могли бы вы создать Асинхронный метод , чтобы вы могли продолжать делать другие вещи, пока метод "занято" завершается?

0 голосов
/ 11 сентября 2009

Методы не имеют тайм-аутов в C #, если только вы в отладчике или ОС не считаете, что ваше приложение «зависло». Даже тогда обработка все еще продолжается, и пока вы не убьете приложение, ответ будет возвращен, и приложение продолжит работать.

У вызовов в базы данных могут быть тайм-ауты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...