2014-02-10 3 views
3

У меня есть этот метод WaitForReaderArrival который, как показано ниже: (Работает все время ожидания для читателя, чтобы прибыть)Ожидание чего-то случится - асинхронная или синхронная модель?

 public void WaitForReaderArrival() 
     { 
      do 
      { 
       if (ReaderArrived()) 
       { 
        break; 
       } 

       System.Threading.Thread.Sleep(1000); 
      } while (ReaderArrived() == false); 
     } 

И я жду для читателя, чтобы прибыть с помощью,

await Task.Run(new Action(WaitForReaderArrival)); 
if (ReaderArrived()) 
{ 
     //Raise an ReaderArrived here! 
    ..//blah blah 
} 

Один мой коллега попросил меня изменить эту строку только

WaitForReaderArrival(); 
if (ReaderArrived()) 
{ 
    //Raise an ReaderArrived here! 
    ..//blah blah 
} 

Возникает вопрос:

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

  2. Что в приведенном выше правильном способе ждать, чтобы что-то произошло, а затем продолжалось?

+0

Скорее всего, должно быть какое-то внешнее событие, которое происходит, когда «читатель приходит», как пользовательский ввод, сообщение сокета, данные о входящем последовательном порту и т. Д. Есть ли что-нибудь подобное? – Noseratio

+0

№. Библиотека, которую я пишу, выставляет это событие и поднимается при ударе вышеописанного кода. –

+2

Код, который вы используете, - это немного улучшенная версия [занятой очереди ожидания] (http://en.wikipedia.org/wiki/Busy_waiting), которая опроса для чего-то с дросселированием. ** Если у вас нет других способов получения уведомлений об изменении **, то разгрузка такого цикла на поток пула с 'waitait Task.Run', вероятно, является лучшей вещью, которую вы можете сделать. – Noseratio

ответ

5

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

Код, который вы используете, - это немного улучшенная версия the busy waiting loop, которая является опросом для чего-то с дросселированием. Если у вас нет каких-либо других способов получения уведомления о смене, вы можете разгрузить эту петлю в пул потоков, как вы делаете уже с await Task.Run, или еще лучше, используйте Task.Delay:

public async Task WaitForReaderArrivalAsync() 
{ 
    while (!ReaderArrived()) 
    { 
     await Task.Delay(1000).ConfigureAwait(false); 
    } 
} 

Один из моих сотрудников попросил меня изменить вышеприведенную строку ... Что в выше - это правильный способ подождать, чтобы что-то произошло, а затем продолжалось?

Ваш коллега ошибается. Если вы позвоните своему оригиналу WaitForReaderArrival, не обернув его await Task.Run или позвоните по предложенной выше версии как WaitForReaderArrivalAsync().Wait(), вы заблокируете поток пользовательского интерфейса. Чтобы сохранить сообщение цикл UI нить функционал, вы должны сделать свой код "Async All the Way":

// top-level event handler 
async void Button_Click(object sender, EventArgs e) 
{ 
    await WaitForReaderArrivalAsync(); 
    MessageBox.Show("ReaderArrived!"); 
} 

Это правильный способ вызова его. По идее, он очень похож на проверку ReaderArrived на событие таймера, но async/await дает удобный линейный псевдосинхронный поток кода.

Обратите внимание, есть популярный антишаблон который делает занят ждем с DoEvents держать UI отзывчивым, эффективно создавая вложенную цикл обработки сообщений в потоке пользовательского интерфейса:

public void WaitForReaderArrival() 
{ 
    while (!ReaderArrived()) 
    { 
     Application.DoEvents(); 
     System.Threading.Thread.Sleep(100); 
    } 
} 

Doing так неправильно: Keeping your UI Responsive and the Dangers of Application.DoEvents.

+0

Возможно, этот код не работает в потоке пользовательского интерфейса. – svick

+0

@svick, OP разъяснил, что это поток пользовательского интерфейса, но в случае не-UI-потока я все равно буду придерживаться 'await Task.Delay (1000)', если интервал опроса не должен быть очень маленьким. – Noseratio

0

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

2

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

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

Если это поток пользовательского интерфейса, вы, скорее всего, не хотите его блокировать. Используйте «ожидание».

Если это выделенный рабочий поток, вы, скорее всего, do хотите его заблокировать. Используйте синхронную форму.

Я должен указать, что при строгом анализе второй if (ReaderArrived()) ошибочен. Это должно быть утверждение, поскольку нет ничего полезного в противном случае.

Кроме того, подумайте об избежании ожидания «занятого сна». Обычно это плохой способ сделать это.

И, наконец, вы действительно должны привыкнуть к идее поговорить с вашими коллегами, прежде чем приходить сюда. :)

0

Что в приведенном выше правильном способе ждать чего-то, и затем продолжить?

Вы можете перейти к продолжению (a.k.a.обратный вызов) для вашей процедуры:

public void WaitForReaderArrival(Action callback) 
{ 
    do 
    { 
     if (ReaderArrived()) 
     { 
      break; 
     } 

     System.Threading.Thread.Sleep(1000); 
    } while (ReaderArrived() == false); 

    callback(); 
} 

Пример использования:

WaitForReaderArrival(() => 
    { 
     // Raise an ReaderArrived here! 
     // ...blah blah 
    }); 

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

Дело в том, что где-то в вашем приложении вам нужно будет подождать Reader. Даже когда вы выполняете ожидание в другом фоновом потоке, вам все равно придется дождаться окончания этого потока.

Моя единственная проблема заключается в том, что использование Thread.Sleep() в потоке пользовательского интерфейса заморозит ваше приложение. Рассмотрим подход, основанный на событиях.

+0

Использование продолжения, когда вы можете использовать 'await', обычно является плохим. 'await' делает код намного чище и понятнее. – svick

+0

Верно, но тогда вы все еще используете 'Задачу'. Его задача (каламбур) заключалась в том, чтобы преобразовать код в обычный синхронный код. Мое предлагаемое решение в основном представляет собой шаблон события, но без использования событий C#. –

Смежные вопросы