Laboratory 9

by Paweł Paduch published 2024/11/28 12:37:00 GMT+1, last modified 2024-11-28T14:55:16+01:00
Task 3 and Parallel operations
  1. Getting Started [0.5 pts]
    • Create a new solution with, a .NET Core console project.
    • Demonstrate the functionality of the following function:
       private static Task<int[]> calculateSomethingAsync(int size)
       {
           return Task.Factory.StartNew<int[]>((s) => {
               if (s==null) { throw new ArgumentNullException(nameof(s)); }
               int[] result = new int[(int)s];
               for (int i = 0; i < (int)s; i++)
               {
                   Thread.SpinWait(30000000);
                   result[i] = Random.Shared.Next(10);
                   Console.WriteLine($"I calculated element {i} as [{result[i]}]");
               }
               return result;
           },size);
       }
  2. Progress Reporting [0.5 pts]
    • Overload the above function so that instead of the message "I calculated element...", it reports using the IProgress<(int,int)> interface.
    • Include the possibility of passing null instead of Progress.
    • Demonstrate the functionality by adding a handler for the ProgressChanged event, printing the iteration number and the generated value.

  3. Cancellation [0.5 pts]
    • Add the ability to cancel the above method using a CancellationToken.
    • The method should check at each iteration if a cancellation request has been made and throw an exception with an appropriate message, e.g., "Cancellation requested".
    • Run the application and test the cancellation using CancelAfter(5000) (from a CancellationTokenSource object). This will request cancellation after 5 seconds.
    • In Main method, catch the generated exception. You can use AggregateException.Flatten().

  4. Optional use of continueWith [0.5 pts]
    • On the created task from the calculateSomethingAsync method, execute ContinueWith in case of an error (TaskContinuationOptions.NotOnRanToCompletion). This will create an alternative task, let's call it onFaultTask.
    • Print the error message passed from the predecessor.
    • Similarly, using ContinueWith, create a task that displays the contents of the returned array but only in case of successful completion (TaskContinuationOptions.OnlyOnRanToCompletion).
    • Wait for both tasks using Task.WaitAll. Here, creating an array of both tasks is required.
    • Catch the exception thrown by the alternative task.
    • Test by commenting/uncommenting CancelAfter(5000).

  5. Using ParallelFor [0.5 pts]
    • Create a new project.
    • Create a simple single-threaded program that generates an array with 10 million random elements.
    • You can use the method
      static int[] GenerateRandomArray(int size) 
      {
      Random random = new Random();
      int[] array = new int[size];
      for (int i = 0; i < size; i++)
      {
      array[i] = random.Next(10);
      }
      return array;
      }
    • Sum all elements using a single-threaded Linq expression
      foreach (int number in numbers) sum += number;
    • Measure the execution time.

  6. Based on the above, conduct experiments with parallel summation using: [1 pt.]
    • Parallel.ForEach(numbers, number => sum += number); Measure the time and check if the sum is identical..
    • Make secure the summation using a lock. Measure the time, check the correctness of the results.
    • Perform summation using the single-threaded Linq method numbers.Sum(number => number); Measure the time, check the correctness of the results.
    • Do the same for the PLINQ query numbers.AsParallel().ForAll(number => sum += number); Measure the time, check the correctness of the results.
    • Make secure the above calculations using a lock. Measure the time, check the correctness of the results.
    • Perform summation using the sum from PLINQ in two ways:
      • numbers.AsParallel().Sum(number => number);
      • numbers.AsParallel().Sum();
    • Measure the time and check the correctness of the results. However, do this by running the program with the first case, then with the second, and then with both. Compare the results.

  7. Perform summation on regular tasks [0.5 pts.]
    • To read the number of processors, use Environment.ProcessorCount.
    • Wait for the tasks to complete and sum their results.
      double[] partialResults = Task.WhenAll(tasks).Result;
      sum = partialResults.Sum();
    • Of course, measure the time and verify the correctness of the data.

  8. Summation with calculation [1 pt.]
    • Perform all tests for the example from points 6 and 7, but sum the results of the function
      static double calculatedValue(double value) 
      {
      return (Math.Sin(Math.Sin(value * value) * Math.Cos(value * value) / Math.PI) * Math.Sin(Math.Sin(value * value) * Math.Cos(value * value) / Math.PI)) > 1 ? 0 : 1; //finally it always returns 1 to simplify checking
      }
    • For example, for a single-threaded operation:
       foreach (int number in numbers)
      {
      sum += calculatedValue(number);
      }