2013-09-08 2 views
1

Мой вопрос основан на статье Best Practices in Asynchronous ProgrammingАсинхронный/Await обработка исключений

Так я этот код

async static void AsyncVersion() 
    { 
     Stopwatch sw = Stopwatch.StartNew(); 
     string url1 = "http://rsdn.ru"; 
     string url2 = "http://gotdotnet.ru"; 
     string url3 = "http://blogs.msdn.com"; 

     var webRequest1 = WebRequest.Create(url1); 
     Console.WriteLine("Before webRequest1.GetResponseAsync(). Thread Id: {0}", 
      Thread.CurrentThread.ManagedThreadId); 
     ... 

так что этот код кидает исключение, например, когда я не инет соединение. Поэтому, когда я следую указаниям msdn и меняю подпись метода на Task (вместо void), но после этого он поглощает все исключения, но hey не обрабатывает внешний блок catch.

Весь код ниже

using System; 
using System.Diagnostics; 
using System.Net; 
using System.Threading; 
using System.Threading.Tasks; 

namespace ConsoleApplication8 
{ 
    class Program 
    { 
     async static Task AsyncVersion() 
     { 
      Stopwatch sw = Stopwatch.StartNew(); 
      string url1 = "http://rsdn.ru"; 
      string url2 = "http://gotdotnet.ru"; 
      string url3 = "http://blogs.msdn.com"; 

      var webRequest1 = WebRequest.Create(url1); 
      Console.WriteLine("Before webRequest1.GetResponseAsync(). Thread Id: {0}", 
       Thread.CurrentThread.ManagedThreadId); 

      var webResponse1 = await webRequest1.GetResponseAsync(); 
      Console.WriteLine("{0} : {1}, elapsed {2}ms. Thread Id: {3}", url1, 
       webResponse1.ContentLength, sw.ElapsedMilliseconds, 
       Thread.CurrentThread.ManagedThreadId); 

      var webRequest2 = WebRequest.Create(url2); 
      Console.WriteLine("Before webRequest2.GetResponseAsync(). Thread Id: {0}", 
       Thread.CurrentThread.ManagedThreadId); 

      var webResponse2 = await webRequest2.GetResponseAsync(); 
      Console.WriteLine("{0} : {1}, elapsed {2}ms. Thread Id: {3}", url2, 
       webResponse2.ContentLength, sw.ElapsedMilliseconds, 
       Thread.CurrentThread.ManagedThreadId); 

      var webRequest3 = WebRequest.Create(url3); 
      Console.WriteLine("Before webRequest3.GetResponseAsync(). Thread Id: {0}", 
       Thread.CurrentThread.ManagedThreadId); 
      var webResponse3 = await webRequest3.GetResponseAsync(); 
      Console.WriteLine("{0} : {1}, elapsed {2}ms. Thread Id: {3}", url3, 
       webResponse3.ContentLength, sw.ElapsedMilliseconds, 
       Thread.CurrentThread.ManagedThreadId); 
     } 
     static void Main(string[] args) 
     { 

      try 
      { 
       Console.WriteLine("Main thread id: {0}", Thread.CurrentThread.ManagedThreadId); 
       Task task = new Task(() => AsyncVersion()); 
       task.Start(); 
       Console.WriteLine("Right after AsyncVersion() method call"); 
       //Ожидаем завершения асинхронной операции 
       task.Wait(); 
       Console.WriteLine("Asyncronous task finished!"); 

      } 
      catch (Exception e) 
      { 
       //Все исключения в TPL пробрасываются обернутые в AggregateException 
       Console.WriteLine("Exceptopn: {0}", e.Message); 
      } 
      Console.ReadLine(); 
     } 
    } 
} 

старой версии:

using System; 
using System.Diagnostics; 
using System.Net; 
using System.Threading; 
using System.Threading.Tasks; 

namespace ConsoleApplication8 
{ 
    class Program 
    { 
     async static void AsyncVersion() 
     { 
      Stopwatch sw = Stopwatch.StartNew(); 
      string url1 = "http://rsdn.ru"; 
      string url2 = "http://gotdotnet.ru"; 
      string url3 = "http://blogs.msdn.com"; 

      var webRequest1 = WebRequest.Create(url1); 
      Console.WriteLine("Before webRequest1.GetResponseAsync(). Thread Id: {0}", 
       Thread.CurrentThread.ManagedThreadId); 

      var webResponse1 = await webRequest1.GetResponseAsync(); 
      Console.WriteLine("{0} : {1}, elapsed {2}ms. Thread Id: {3}", url1, 
       webResponse1.ContentLength, sw.ElapsedMilliseconds, 
       Thread.CurrentThread.ManagedThreadId); 

      var webRequest2 = WebRequest.Create(url2); 
      Console.WriteLine("Before webRequest2.GetResponseAsync(). Thread Id: {0}", 
       Thread.CurrentThread.ManagedThreadId); 

      var webResponse2 = await webRequest2.GetResponseAsync(); 
      Console.WriteLine("{0} : {1}, elapsed {2}ms. Thread Id: {3}", url2, 
       webResponse2.ContentLength, sw.ElapsedMilliseconds, 
       Thread.CurrentThread.ManagedThreadId); 

      var webRequest3 = WebRequest.Create(url3); 
      Console.WriteLine("Before webRequest3.GetResponseAsync(). Thread Id: {0}", 
       Thread.CurrentThread.ManagedThreadId); 
      var webResponse3 = await webRequest3.GetResponseAsync(); 
      Console.WriteLine("{0} : {1}, elapsed {2}ms. Thread Id: {3}", url3, 
       webResponse3.ContentLength, sw.ElapsedMilliseconds, 
       Thread.CurrentThread.ManagedThreadId); 
     } 
     static void Main(string[] args) 
     { 

      try 
      { 
       Console.WriteLine("Main thread id: {0}", Thread.CurrentThread.ManagedThreadId); 
       Task task = new Task(AsyncVersion); 
       task.Start(); 
       Console.WriteLine("Right after AsyncVersion() method call"); 
       //Ожидаем завершения асинхронной операции 
       task.Wait(); 
       Console.WriteLine("Asyncronous task finished!"); 

      } 
      catch (System.AggregateException e) 
      { 
       //Все исключения в TPL пробрасываются обернутые в AggregateException 
       Console.WriteLine("AggregateException: {0}", e.InnerException.Message); 
      } 
      Console.ReadLine(); 
     } 
    } 
} 
+0

Возможно, вы захотите переупорядочить некоторые из ваших ожиданий, сейчас вы по-прежнему выполняете каждый запрос по одному, если вы сохранили 'Task' от каждого' GetResponseAsync() 'вместо того, чтобы ждать сразу, вы можете позволить всем 3 запускать сразу а затем в конце вы ожидаете. Поэтому для ваших ответов измените свой код на 'var webResponse1Task = webRequest1.GetResponseAsync();' затем в нижней части вашей функции выполните 'var webResponse1 = wait webResponse1Task; var webResponse2 = ожидание webResponse2Task; var webResponse3 = ожидание webResponse3Task; ' –

ответ

10
new Task(() => AsyncVersion()) 

Это проблематичная часть. Конструктор Task не понимает async, поэтому он игнорирует Task, возвращенный с AsyncVersion. (Тот факт, что вы должны были использовать лямбда вместо написания AsyncVersion непосредственно должны насторожить вас, что-то странное происходит.)

У вас есть несколько вариантов, как это исправить (лучшие варианты последних):

  1. Используйте Task<Task> и Wait() для внутреннего Task тоже:

    Task<Task> task = new Task<Task>(AsyncVersion); 
    task.Start(); 
    task.Result.Wait(); 
    
  2. Unwrap() Используйте для изменения Task<Task> в Task, представляющий как Task S:

    Task<Task> task = new Task<Task>(AsyncVersion); 
    task.Start(); 
    task.Unwrap().Wait(); 
    
  3. Использование Task.Run(), который действительно понимает async:

    Task task = Task.Run(() => AsyncVersion()); 
    task.Wait(); 
    
  4. Не начать Task вообще, просто вызовите async метод:

    Task task = AsyncVersion(); 
    task.Wait(); 
    
+3

+1. ИМО - лучший вариант (4) - просто вызовите метод async и 'Wait' в возвращаемой задаче. Примечание для Алекса: Обычно вы * не * хотите вызывать 'Wait' или' Result' в асинхронных задачах, но вы должны в этом случае, потому что это консольное приложение. Если вы делали это в приложении WinForms/WPF/ASP.NET, вы должны использовать 'await' вместо' Wait'. –