1

我的问题基于文章异步编程中的最佳实践

所以我有这个代码

    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);
        ...

所以这段代码会抛出异常,例如当我没有 inet 连接时。因此,当我遵循 msdn 的指导并将方法的签名更改为 Task(而不是 void)时,但在此之后它会吞噬所有异常,但它们不会被外部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();
        }
    }
}
4

1 回答 1

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

这是有问题的部分。构造Task函数不理解async,所以它忽略了Taskfrom 的返回AsyncVersion。(您必须使用 lambda 而不是直接编写的事实AsyncVersion应该提醒您正在发生一些奇怪的事情。)

你有几个选项来解决这个问题(最好的选项最后):

  1. Task<Task>也用于Wait()内部Task

    Task<Task> task = new Task<Task>(AsyncVersion);
    task.Start();
    task.Result.Wait();
    
  2. 用于将表示两个s 的Unwrap()更改为Task<Task>TaskTask

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

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

    Task task = AsyncVersion();
    task.Wait();
    
于 2013-09-08T19:26:24.453 回答