彩票走势图

.NET 4并行编程时Task执行和异常处理

转帖|其它|编辑:郝浩|2010-06-10 09:49:16.000|阅读 908 次

概述:在上篇文章中介绍了如果从Task中获取执行后的结果:在Task执行完成之后调用Task.Result获取。其实也可以用其他的方法等待Task执行完成而不获取结果,这是很有用的:如果你想等待一个task完成之后再去做其他的事情。

# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>

  在上篇文章中介绍了如果从Task中获取执行后的结果:在Task执行完成之后调用Task.Result获取。其实也可以用其他的方法等待Task执行完成而不获取结果,这是很有用的:如果你想等待一个task完成之后再去做其他的事情。而且我们还可以等待一个task执行完成,或者等待所有的task执行完成,或者等待很多task中的一个执行完成。因为Task是由内部的Scheduler管理的,调用wait方法,其实就是我们在监控task的执行,看看这个task是否执行完了,如果完成,那么wanit方法就返回true,反之。

  1. 等待Task执行完成

  1.1等待单独的一个Task执行完成

  我们可以用Wait()方法来一直等待一个Task执行完成。当task执行完成,或者被cancel,或者抛出异常,这个方法才会返回。可以使用Wait()方法的不同重载。举个例子:

  代码


        static void Main(string[] args)   
       {   
        // create the cancellation token source   
        CancellationTokenSource tokenSource = new CancellationTokenSource();   
        // create the cancellation token   
        CancellationToken token = tokenSource.Token;   
        // create and start the first task, which we will let run fully   
        Task task = createTask(token);   
        task.Start();   
 
        // wait for the task   
        Console.WriteLine("Waiting for task to complete.");   
        task.Wait();   
        Console.WriteLine("Task Completed.");   
 
        // create and start another task   
        task = createTask(token);   
        task.Start();   
        Console.WriteLine("Waiting 2 secs for task to complete.");   
        bool completed = task.Wait(2000);   
        Console.WriteLine("Wait ended - task completed: {0}", completed);   
 
        // create and start another task   
        task = createTask(token);   
        task.Start();   
        Console.WriteLine("Waiting 2 secs for task to complete.");   
        completed = task.Wait(2000, token);   
        Console.WriteLine("Wait ended - task completed: {0} task cancelled {1}",   
        completed, task.IsCanceled);   
 
        // wait for input before exiting   
        Console.WriteLine("Main method complete. Press enter to finish.");   
        Console.ReadLine();   
    }   
 
    static Task createTask(CancellationToken token)   
    {   
        return new Task(() =>   
        {   
            for (int i = 0; i < 5; i++)   
            {   
                // check for task cancellation   
                token.ThrowIfCancellationRequested();   
                // print out a message   
                Console.WriteLine("Task - Int value {0}", i);   
                // put the task to sleep for 1 second   
                token.WaitHandle.WaitOne(1000);   
            }   
        }, token);   
    } 

 

  从上面的例子可以看出,wait方法子task执行完成之后会返回true。

  注意:当在执行的task内部抛出了异常之后,这个异常在调用wait方法时会被再次抛出。后面再"异常处理篇"会讲述。

  1.2.等待多个task

  我们也可以用WaitAll()方法来一直到等待多个task执行完成。只有当所有的task执行完成,或者被cancel,或者抛出异常,这个方法才会返回。WiatAll()方法和Wait()方法一样有一些重载。

  注意:如果在等在的多个task之中,有一个task抛出了异常,那么调用WaitAll()方法时就会抛出异常。

  代码


static void Main(string[] args)   
    {   
        // create the cancellation token source   
        CancellationTokenSource tokenSource = new CancellationTokenSource();   
        // create the cancellation token   
        CancellationToken token = tokenSource.Token;   
        // create the tasks   
        Task task1 = new Task(() =>   
        {   
            for (int i = 0; i < 5; i++)   
            {   
                // check for task cancellation   
                token.ThrowIfCancellationRequested();   
                // print out a message   
                Console.WriteLine("Task 1 - Int value {0}", i);   
                // put the task to sleep for 1 second   
                token.WaitHandle.WaitOne(1000);   
            }   
            Console.WriteLine("Task 1 complete");   
        }, token);   
        Task task2 = new Task(() =>   
        {   
            Console.WriteLine("Task 2 complete");   
        }, token);   
 
        // start the tasks   
        task1.Start();   
        task2.Start();   
        // wait for the tasks   
        Console.WriteLine("Waiting for tasks to complete.");   
        Task.WaitAll(task1, task2);   
        Console.WriteLine("Tasks Completed.");   
        // wait for input before exiting   
        Console.WriteLine("Main method complete. Press enter to finish.");   
        Console.ReadLine();   
    }

 

  在上面的例子中,首先创建了两个task,注意我们创建的是可以被cancel的task,因为使用CancellationToken。而且在第一个task中还是用waitOne()休眠方法,其实目的很简单:使得这个task的运行时间长一点而已。之后我们就调用了WaitAll()方法,这个方法一直到两个task执行完成之后才会返回的。

1.3.等待多个task中的一个task执行完成

  可以用WaitAny()方法来等待多个task中的一个task执行完成。通俗的讲就是:有很多的task在运行,调用了WaitAny()方法之后,只要那些运行的task其中有一个运行完成了,那么WaitAny()就返回了。

  代码


static void Main(string[] args)   
    {   
        // create the cancellation token source   
        CancellationTokenSource tokenSource = new CancellationTokenSource();   
        // create the cancellation token   
        CancellationToken token = tokenSource.Token;   
        // create the tasks   
        Task task1 = new Task(() =>   
        {   
            for (int i = 0; i < 5; i++)   
            {   
                // check for task cancellation   
                token.ThrowIfCancellationRequested();   
                // print out a message   
                Console.WriteLine("Task 1 - Int value {0}", i);   
                // put the task to sleep for 1 second   
                token.WaitHandle.WaitOne(1000);   
            }   
            Console.WriteLine("Task 1 complete");   
        }, token);   
        Task task2 = new Task(() =>   
        {   
            Console.WriteLine("Task 2 complete");   
        }, token);   
 
        // start the tasks   
        task1.Start();   
        task2.Start();   
        // wait for the tasks   
        Console.WriteLine("Waiting for tasks to complete.");   
        Task.WaitAll(task1, task2);   
        Console.WriteLine("Tasks Completed.");   
        // wait for input before exiting   
        Console.WriteLine("Main method complete. Press enter to finish.");   
        Console.ReadLine();   
    } 

 

  2. Task中的异常处理

  在并行编程(TPL)中另外一个已经标准化了的操作就是"异常处理"。而且在并行编程中异常处理显得尤为重要,因为并行编程时与系统中的线程相关的,出了异常,你开发的程序就很有可能崩溃。

  下面就详细介绍TPL中异常处理操作。

  a.处理基本的异常。

  在操作task的时候,只要出现了异常,.NET Framework就会把这些异常记录下来。例如在执行Task.Wait(),Task.WaitAll(),Task.WaitAny(),Task.Result.不管那里出现了异常,最后抛出的就是一个System.AggregateException.

  System.AggregateException时用来包装一个或者多个异常的,这个类时很有用的,特别是在调用Task.WaitAll()方法时。因为在Task.WaitAll()是等待多个task执行完成,如果有任意task执行出了异常,那么这个异常就会被记录在System.AggregateException中,不同的task可能抛出的异常不同,但是这些异常都会被记录下来。

  下面就是给出一个例子:在例子中,创建了两个task,它们都抛出异常。然后主线程开始运行task,并且调用WaitAll()方法,然后就捕获抛出的System.AggregateException,显示详细信息。

  代码


 static void Main(string[] args)    
    {    
  
        // create the tasks    
        Task task1 = new Task(() =>    
        {    
            ArgumentOutOfRangeException exception = new ArgumentOutOfRangeException();    
            exception.Source = "task1";    
            throw exception;    
        });    
        Task task2 = new Task(() =>    
        {    
            throw new NullReferenceException();    
        });    
        Task task3 = new Task(() =>    
        {    
            Console.WriteLine("Hello from Task 3");    
        });    
        // start the tasks    
        task1.Start(); task2.Start(); task3.Start();    
        // wait for all of the tasks to complete    
        // and wrap the method in a try...catch block    
        try   
        {    
            Task.WaitAll(task1, task2, task3);    
        }    
        catch (AggregateException ex)    
        {    
            // enumerate the exceptions that have been aggregated    
            foreach (Exception inner in ex.InnerExceptions)    
            {    
                Console.WriteLine("Exception type {0} from {1}",    
                inner.GetType(), inner.Source);    
            }    
        }    
        // wait for input before exiting    
        Console.WriteLine("Main method complete. Press enter to finish.");    
        Console.ReadLine();    
    } 

 

  从上面的例子可以看出,为了获得被包装起来的异常,需要调用System.AggregateException的InnerExceptions属性,这个属性返回一个异常的集合,然后就可以遍历这个集合。

  而且从上面的例子可以看到:Exeception.Source属性被用来指明task1的异常时ArgumentOutRangeException.

b.使用迭代的异常处理Handler

  一般情况下,我们需要区分哪些异常需要处理,而哪些异常需要继续往上传递。AggregateException类提供了一个Handle()方法,我们可以用这个方法来处理

  AggregateException中的每一个异常。在这个Handle()方法中,返回true就表明,这个异常我们已经处理了,不用抛出,反之。

  在下面的例子中,抛出了一个OperationCancelException,在之前的task的取消一文中,已经提到过:当在task中抛出这个异常的时候,实际上就是这个task发送了取消的请求。下面的代码中,描述了如果在AggregateException.Handle()中处理不同的异常。

  代码


static void Main(string[] args)   
    {   
        // create the cancellation token source and the token   
        CancellationTokenSource tokenSource = new CancellationTokenSource();   
        CancellationToken token = tokenSource.Token;   
        // create a task that waits on the cancellation token   
        Task task1 = new Task(() =>   
        {   
            // wait forever or until the token is cancelled   
            token.WaitHandle.WaitOne(-1);   
            // throw an exception to acknowledge the cancellation   
            throw new OperationCanceledException(token);   
        }, token);   
        // create a task that throws an exception   
        Task task2 = new Task(() =>   
        {   
            throw new NullReferenceException();   
        });   
        // start the tasks   
        task1.Start(); task2.Start();   
        // cancel the token   
        tokenSource.Cancel();   
        // wait on the tasks and catch any exceptions   
        try  
        {   
            Task.WaitAll(task1, task2);   
        }   
        catch (AggregateException ex)   
        {   
            // iterate through the inner exceptions using   
            // the handle method   
            ex.Handle((inner) =>   
            {   
                if (inner is OperationCanceledException)   
                {   
 
                    // ...handle task cancellation...   
                    return true;   
                }   
                else  
                {   
                    // this is an exception we don't know how   
                    // to handle, so return false   
                    return false;   
                }   
            });   
        }   
        // wait for input before exiting   
        Console.WriteLine("Main method complete. Press enter to finish.");   
        Console.ReadLine();   
    } 

 


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn

文章转载自:网络转载

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP