Поделиться через


Практическое руководство. Ожидание завершения выполнения одной или нескольких задач

В этом примере показано использование метода Wait или его эквивалента в классе Task<TResult> для ожидания одной задачи. В нем также показано использование статических методов WaitAll и WaitAny для ожидания нескольких задач.

Пример

' How to: Wait on One or More Tasks to Complete
Imports System.Threading
Imports System.Threading.Tasks

Module WaitOnTasks

    Dim rand As New Random()
    Sub Main()

        ' Wait on a single task with no timeout specified.
        Dim taskA = Task.Factory.StartNew(Sub() DoSomeWork(10000000))
        taskA.Wait()
        Console.WriteLine("taskA has completed.")


        ' Wait on a single task with a timeout specified.
        Dim taskB = Task.Factory.StartNew(Sub() DoSomeWork(10000000))
        taskB.Wait(100) 'Wait for 100 ms.

        If (taskB.IsCompleted) Then
            Console.WriteLine("taskB has completed.")
        Else
            Console.WriteLine("Timed out before task2 completed.")
        End If

        ' Wait for all tasks to complete.
        Dim myTasks(9) As Task
        For i As Integer = 0 To myTasks.Length - 1
            myTasks(i) = Task.Factory.StartNew(Sub() DoSomeWork(10000000))
        Next
        Task.WaitAll(myTasks)

        ' Wait for first task to complete.
        Dim tasks2(2) As Task(Of Double)

        ' Try three different approaches to the problem. Take the first one.
        tasks2(0) = Task(Of Double).Factory.StartNew(Function() TrySolution1())
        tasks2(1) = Task(Of Double).Factory.StartNew(Function() TrySolution2())
        tasks2(2) = Task(Of Double).Factory.StartNew(Function() TrySolution3())


        Dim index As Integer = Task.WaitAny(tasks2)
        Dim d As Double = tasks2(index).Result
        Console.WriteLine("task(0) completed first with result of {1}.", index, d)
        Console.ReadKey()

    End Sub


    ' Dummy Functions to Simulate Work

    Function DoSomeWork(ByVal val As Integer)
        ' Pretend to do something.
        Thread.SpinWait(val)
    End Function

    Function TrySolution1()

        Dim i As Integer = rand.Next(1000000)
        ' Simulate work by spinning
        Thread.SpinWait(i)
        Return i
    End Function
    Function TrySolution2()

        Dim i As Integer = rand.Next(1000000)
        ' Simulate work by spinning
        Thread.SpinWait(i)
        Return i
    End Function
    Function TrySolution3()

        Dim i As Integer = rand.Next(1000000)
        ' Simulate work by spinning
        Thread.SpinWait(i)
        Thread.SpinWait(1000000)
        Return i
    End Function

End Module

    using System;   
    using System.Threading;
    using System.Threading.Tasks;

    class Program
    {
        static Random rand = new Random();
        static void Main(string[] args)
        {
            // Wait on a single task with no timeout specified.
            Task taskA = Task.Factory.StartNew(() => DoSomeWork(10000000));
            taskA.Wait();
            Console.WriteLine("taskA has completed.");


            // Wait on a single task with a timeout specified.
            Task taskB = Task.Factory.StartNew(() => DoSomeWork(10000000));
            taskB.Wait(100); //Wait for 100 ms.

            if (taskB.IsCompleted)
                Console.WriteLine("taskB has completed.");
            else
                Console.WriteLine("Timed out before taskB completed.");

            // Wait for all tasks to complete.
            Task[] tasks = new Task[10];
            for (int i = 0; i < 10; i++)
            {
                tasks[i] = Task.Factory.StartNew(() => DoSomeWork(10000000));
            }
            Task.WaitAll(tasks);

            // Wait for first task to complete.
            Task<double>[] tasks2 = new Task<double>[3];

            // Try three different approaches to the problem. Take the first one.
            tasks2[0] = Task<double>.Factory.StartNew(() => TrySolution1());
            tasks2[1] = Task<double>.Factory.StartNew(() => TrySolution2());
            tasks2[2] = Task<double>.Factory.StartNew(() => TrySolution3());


            int index = Task.WaitAny(tasks2);
            double d = tasks2[index].Result;
            Console.WriteLine("task[{0}] completed first with result of {1}.", index, d);

            Console.ReadKey();
        }


        static void DoSomeWork(int val)
        {
            // Pretend to do something.
            Thread.SpinWait(val);
        }

        static double TrySolution1()
        {
            int i = rand.Next(1000000);
            // Simulate work by spinning
            Thread.SpinWait(i); 
            return DateTime.Now.Millisecond;
        }
        static double TrySolution2()
        {
            int i = rand.Next(1000000);
            // Simulate work by spinning
            Thread.SpinWait(i); 
            return DateTime.Now.Millisecond;
        }
        static double TrySolution3()
        {
            int i = rand.Next(1000000);
            // Simulate work by spinning
            Thread.SpinWait(i); 
            Thread.SpinWait(1000000);
            return DateTime.Now.Millisecond;
        }


    }

Для простоты в этих примерах не представлен код обработки исключений или код отмены. В большинстве случаев метод Wait необходимо заключать в блок try-catch, поскольку ожидание — это механизм, согласно которому программный код обрабатывает исключения, возникающие из любой задачи. Дополнительные сведения см. в разделе Практическое руководство. Обработка исключений, создаваемых задачами. Если задача является отменяемой, необходимо проверить свойство IsCanceled или IsCancellationRequested() перед попыткой использования задачи или ее свойства Result(). Дополнительные сведения см. в разделе Практическое руководство. Отмена задачи и ее дочерних элементов.

См. также

Основные понятия

Лямбда-выражения в PLINQ и библиотеке параллельных задач

Другие ресурсы

Параллелизм задач (библиотека параллельных задач)