2012-04-30 2 views
0

Я пытаюсь дождаться результата задачи в .NET 4, как вы можете, используя ключевое слово await в .NET 4.5. Я просто не могу понять, как это сделать, хотя ...Неблокирующий Task.wait в .NET 4?

Моего кода (чтобы доказать, что я по крайней мере пытаюсь):

Private Function GetXDocumentFromWebLocationAsync(ByVal request As WebRequest) As XDocument 
     Dim queryTask As Task(Of WebResponse) 
     queryTask = task(Of WebResponse).Factory.FromAsync(AddressOf request.BeginGetResponse, AddressOf request.EndGetResponse, Nothing, Nothing) 
     Return XDocument.Load(queryTask.Result.GetResponseStream) 
    End Function 

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

Что такое секретный соус?

+0

'Async CTP ... просто убегает от проблемы.' Я бы сказал, что Async CTP «решает» проблему. Кажется, каждый из его собственных ... –

+0

Сортировка, но CTP больше похож на предварительный просмотр того, что принесет .NET 4.5. Не то, что вы используете в производственном коде. А поскольку он основывается на API-интерфейсах задач, с ним можно обойтись, не так ли? –

+1

Ну, я использую его в производственном коде довольно долгое время, но у меня также очень ограниченная база пользователей. :) CTP действительно больше представляет собой предварительный просмотр компиляторов VS11; вы могли бы использовать бета-версию VS11 вместе с «.NET-асинхронным таргетингом», чтобы разработать решение .NET 4, если хотите. Он основывается на задачах - вроде - но делать точный дубликат [много работы] (http://msmvps.com/blogs/jon_skeet/archive/tags/Eduasync/default.aspx). –

ответ

3

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

Но есть и другие способы достижения одного и того же. «Старый» способ сделать это в .Net - это то же самое: WebRequest использует: есть два метода: BeginGetXDocument и EndGetXDocument. Затем вы можете передать делегат методу Begin, который будет выполнен после завершения операции.

Другой способ сделать это - вернуть Task из вашего метода. Чтобы сделать это, вы можете использовать ContinueWith():

Private Function GetXDocumentFromWebLocationAsync(ByVal request As WebRequest) As Task(Of XDocument) 
    Dim queryTask As Task(Of WebResponse) 
    queryTask = Task(Of WebResponse).Factory.FromAsync(
     AddressOf request.BeginGetResponse, AddressOf request.EndGetResponse, Nothing, Nothing) 
    Return queryTask.ContinueWith(
     Function(antecendent) XDocument.Load(antecendent.Result.GetResponseStream)) 
End Function 

Таким образом, потребитель метода может выбрать ждать результата синхронно (с использованием Wait() или Result), или он может использовать ContinueWith() снова.

При использовании ContinueWith() в приложениях GUI вы должны быть осторожны: продолжение выполняется по потоку ThreadPool по умолчанию. Чтобы запустить продолжение в потоке графического интерфейса, вы можете использовать TaskScheduler.FromCurrentSynchronizationContext(). Или метод, специфичный для вашей библиотеки GUI (Dispatcher.Invoke() в WPF, Control.Invoke() в Winforms).

+0

Итак, если я правильно понимаю, я могу связать оставшуюся часть своего кода в вызовах ContinueWith(), чтобы избежать блокировки? –

+0

Да, точно. Но не забывайте, что это изменяет возвращаемый тип вашего метода с 'X' на' Task (Of X) '. Но если вы хотите подождать несколько вещей во всем методе, использование 'ContinueWith()' может сделать ваш код нечитаемым довольно быстрым. Вот где сияет C# 5 'await'. – svick

+0

Я по-прежнему считаю, что это лучше, чем методы begin/end и обработчики событий повсюду! –