异步/等待异常处理

时间:2013-09-08 19:11:49

标签: c# .net asynchronous task-parallel-library async-await

我的问题基于文章Best Practices in Asynchronous Programming

所以我有这段代码

    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();
        }
    }
}

1 个答案:

答案 0 :(得分:10)

new Task(() => AsyncVersion())

这是有问题的部分。 Task构造函数无法理解async,因此忽略了从Task返回的AsyncVersion。 (事实上​​你必须直接使用lambda而不是写AsyncVersion,这应该会提醒你发生了一些奇怪的事情。)

您有多种选择如何解决此问题(最后一个选项):

  1. 同样使用Task<Task>Wait()作为内部Task

    Task<Task> task = new Task<Task>(AsyncVersion);
    task.Start();
    task.Result.Wait();
    
  2. 使用Unwrap()将代表Task<Task>的{​​{1}}更改为Task

    Task
  3. 使用Task<Task> task = new Task<Task>(AsyncVersion); task.Start(); task.Unwrap().Wait(); ,它了解Task.Run()

    async
  4. 根本不要启动Task task = Task.Run(() => AsyncVersion()); task.Wait(); ,只需调用Task方法:

    async