I have to multiply matrix by vector using class Task from TPL (it's labaratory work and I have to). I did it using Parallel For and it works but now I'm stuck because I have no idea how to implement it using tasks.
public static int[] matxvecParallel(int [,] mat, int[] vec)ParallelFor
{
int[] res = new int[mat.GetLength(0)];
Parallel.For(0, mat.GetLength(0), i =>
{
for (int k = 0; k < mat.GetLength(1); k++)
{
res[i] += mat[i, k] * vec[k];
}
});
return res;
}
I did something stupid to find out how tasks works and I still don't understand.
How to change my code?
public static int[] matxvecTask(int[,] mat, int[] vec)
{
int[] res = new int[mat.GetLength(0)];
int countTasks = 4;
Task[] arrayOfTasks = new Task[countTasks];
for (int k = 0; k < mat.GetLength(0); k++)
{
for(int i = 0; i < countTasks; i++)
{
int index = i;
arrayOfTasks[index] = Task.Run(() =>
{
for (int j = 0; j < mat.GetLength(1); j++)
{
res[i] += mat[i, j] * vec[j];
}
});
}
}
return res;
}
To make it work, change this line to use index instead of i:
res[index] += mat[index, j] * vec[j];
When you use i, you fall in the trap of closures.
Then, you should also wait for all the tasks to complete before moving on to the next iteration:
Task.WaitAll(arrayOfTasks);
Now, you will gain absolutely nothing if you replace Parallel.For with tasks. You only make your code more complicated. Both tasks and Parallel will execute your computations on the thread pool. However, Parallel is optimized especially for the purpose and it easier to write and read.
Related
I am working on a project that compares the time bubble and selection sort take. I made two separate programs and combined them into one and now bubble sort is running much faster than selection sort. I checked to make sure that the code wasn't just giving me 0s because of some conversion error and was running as intended. I am using System.Diagnostics; to measure the time. I also checked that the machine was not the problem, I ran it on Replit and got similar results.
{
class Program
{
public static int s1 = 0;
public static int s2 = 0;
static decimal bubblesort(int[] arr1)
{
int n = arr1.Length;
var sw1 = Stopwatch.StartNew();
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
if (arr1[j] > arr1[j + 1])
{
int tmp = arr1[j];
// swap tmp and arr[i] int tmp = arr[j];
arr1[j] = arr1[j + 1];
arr1[j + 1] = tmp;
s1++;
}
}
}
sw1.Stop();
// Console.WriteLine(sw1.ElapsedMilliseconds);
decimal a = Convert.ToDecimal(sw1.ElapsedMilliseconds);
return a;
}
static decimal selectionsort(int[] arr2)
{
int n = arr2.Length;
var sw1 = Stopwatch.StartNew();
// for (int e = 0; e < 1000; e++)
// {
for (int x = 0; x < arr2.Length - 1; x++)
{
int minPos = x;
for (int y = x + 1; y < arr2.Length; y++)
{
if (arr2[y] < arr2[minPos])
minPos = y;
}
if (x != minPos && minPos < arr2.Length)
{
int temp = arr2[minPos];
arr2[minPos] = arr2[x];
arr2[x] = temp;
s2++;
}
}
// }
sw1.Stop();
// Console.WriteLine(sw1.ElapsedMilliseconds);
decimal a = Convert.ToDecimal(sw1.ElapsedMilliseconds);
return a;
}
static void Main(string[] args)
{
Console.WriteLine("Enter the size of n");
int n = Convert.ToInt32(Console.ReadLine());
Random rnd = new System.Random();
decimal bs = 0M;
decimal ss = 0M;
int s = 0;
int[] arr1 = new int[n];
int tx = 1000; //tx is a variable that I can use to adjust sample size
decimal tm = Convert.ToDecimal(tx);
for (int i = 0; i < tx; i++)
{
for (int a = 0; a < n; a++)
{
arr1[a] = rnd.Next(0, 1000000);
}
ss += selectionsort(arr1);
bs += bubblesort(arr1);
}
bs = bs / tm;
ss = ss / tm;
Console.WriteLine("Bubble Sort took " + bs + " miliseconds");
Console.WriteLine("Selection Sort took " + ss + " miliseconds");
}
}
}
What is going on? What is causing bubble sort to be fast or what is slowing down Selection sort? How can I fix this?
I found that the problem was that the Selection Sort was looping 1000 times per method run in addition to the 1000 runs for sample size, causing the method to perform significantly worse than bubble sort. Thank you guys for help and thank you TheGeneral for showing me the benchmarking tools. Also, the array that was given as a parameter was a copy instead of a reference, as running through the loop manually showed me that the bubble sort was doing it's job and not sorting an already sorted array.
To solve your initial problem you just need to copy your arrays, you can do this easily with ToArray():
Creates an array from a IEnumerable.
ss += selectionsort(arr1.ToArray());
bs += bubblesort(arr1.ToArray());
However let's learn how to do a more reliable benchmark with BenchmarkDotNet:
BenchmarkDotNet Nuget
Official Documentation
Given
public class Sort
{
public static void BubbleSort(int[] arr1)
{
int n = arr1.Length;
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
if (arr1[j] > arr1[j + 1])
{
int tmp = arr1[j];
// swap tmp and arr[i] int tmp = arr[j];
arr1[j] = arr1[j + 1];
arr1[j + 1] = tmp;
}
}
}
}
public static void SelectionSort(int[] arr2)
{
int n = arr2.Length;
for (int x = 0; x < arr2.Length - 1; x++)
{
int minPos = x;
for (int y = x + 1; y < arr2.Length; y++)
{
if (arr2[y] < arr2[minPos])
minPos = y;
}
if (x != minPos && minPos < arr2.Length)
{
int temp = arr2[minPos];
arr2[minPos] = arr2[x];
arr2[x] = temp;
}
}
}
}
Benchmark code
[SimpleJob(RuntimeMoniker.Net50)]
[MemoryDiagnoser()]
public class SortBenchmark
{
private int[] data;
[Params(100, 1000)]
public int N;
[GlobalSetup]
public void Setup()
{
var r = new Random(42);
data = Enumerable
.Repeat(0, N)
.Select(i => r.Next(0, N))
.ToArray();
}
[Benchmark]
public void Bubble() => Sort.BubbleSort(data.ToArray());
[Benchmark]
public void Selection() => Sort.SelectionSort(data.ToArray());
}
Usage
static void Main(string[] args)
{
BenchmarkRunner.Run<SortBenchmark>();
}
Results
Method
N
Mean
Error
StdDev
Bubble
100
8.553 us
0.0753 us
0.0704 us
Selection
100
4.757 us
0.0247 us
0.0231 us
Bubble
1000
657.760 us
7.2581 us
6.7893 us
Selection
1000
300.395 us
2.3302 us
2.1796 us
Summary
What have we learnt? Your bubble sort code is slower ¯\_(ツ)_/¯
It looks like you're passing in the sorted array into Bubble Sort. Because arrays are passed by reference, the sort that you're doing on the array is editing the same contents of the array that will be eventually passed into bubble sort.
Make a second array and pass the second array into bubble sort.
What's the performance penalty that I can expect if I'm using Lists over Arrays to solve the Longest Increasing Subsequence?
Will the dynamic nature of Lists improve average performance because we're not dealing with sizes we won't actually use?
PS: Any tips on improving performance while still maintaining some readability?
public static int Run(int[] nums)
{
var length = nums.Length;
List<List<int>> candidates = new List<List<int>>();
candidates.Add(new List<int> { nums[0] });
for (int i = 1; i < length; i++)
{
var valueFromArray = nums[i];
var potentialReplacements = candidates.Where(t => t[t.Count-1] > valueFromArray);
foreach (var collection in potentialReplacements)
{
var collectionCount = collection.Count;
if ((collection.Count > 1 && collection[collectionCount - 2] < valueFromArray) || (collectionCount == 1))
{
collection.RemoveAt(collectionCount - 1);
collection.Add(valueFromArray);
}
}
if (!candidates.Any(t => t[t.Count - 1] >= valueFromArray))
{
var newList = new List<int>();
foreach(var value in candidates[candidates.Count - 1])
{
newList.Add(value);
}
newList.Add(nums[i]);
candidates.Add(newList);
}
}
return candidates[candidates.Count - 1].Count;
}
Depending on the solution the results may vary. Arrays are faster when compared with lists of the same size. How more fast? Lets take a look at the c# solution below. This is a simple O(n^2) solution. I coded a version with arrays only and another one with lists only. I'm running it 1000 times and recording the values for both. Then I just print the average improvement of the array version over the list version. I'm getting over 50% improvement on my computer.
Notice that this solution uses arrays and lists with the same sizes always. Than means I never created an array bigger than the size the lists are gonna grow to in the lists version. Once you start creating arrays with a Max size that may not be filled the comparison stops to be fair.
C# code below:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace hashExample
{
class Program
{
static int RunArray(int[] array)
{
int[] dp = new int[array.Length];
dp[0] = 1;
for (int i = 1; i < array.Length; i++)
{
dp[i] = 1;
for (int j = 0; j < i; j++)
if (array[i] > array[j] && dp[i] < dp[j] + 1)
dp[i] = dp[j] + 1;
}
return dp.Max();
}
static int RunList(List<int> array)
{
List<int> dp = new List<int>(array.Count);
dp.Add(1);
for (int i = 1; i < array.Count; i++)
{
dp.Add(1);
for (int j = 0; j < i; j++)
if (array[i] > array[j] && dp[i] < dp[j] + 1)
dp[i] = dp[j] + 1;
}
return dp.Max();
}
static void Main(string[] args)
{
int arrayLen = 1000;
Random r = new Random();
List<double> values = new List<double>();
Stopwatch clock = new Stopwatch();
Console.WriteLine("Running...");
for (int i = 0; i < 100; i++)
{
List<int> list = new List<int>();
int[] array = new int[arrayLen];
for (int j = 0; j < arrayLen;j++)
{
int e = r.Next();
array[j] = e;
list.Add(e);
}
clock.Restart();
RunArray(array);
clock.Stop();
double timeArray = clock.ElapsedMilliseconds;
clock.Restart();
RunList(list);
clock.Stop();
double timeList = clock.ElapsedMilliseconds;
//Console.WriteLine(Math.Round(timeArray/timeList*100,2) + "%");
values.Add(timeArray / timeList);
}
Console.WriteLine("Arrays are " + Math.Round(values.Average()*100,1) + "% faster");
Console.WriteLine("Done");
}
}
}
I have an array of 921600 numbers between 0 and 255.
I need to check each number whether it's above a threshold or not.
Is it possible to check the first- and second half of the array at the same time, to cut down on run time?
What I mean is, is it possible to run the following two for loops in parallel?
for(int i = 0; i < 921600 / 2; i++)
{
if(arr[i] > 240) counter++;
}
for(int j = 921600 / 2; j < 921600; j++)
{
if(arr[j] > 240) counter++;
}
Thank you in advance!
I suggest using Parallel Linq (PLinq) for this
int[] source = ...
int count = source
.AsParallel() // comment this out if you want sequential version
.Count(item => item > 240);
What you are asking is strictly possible as per below.
int counter = 0;
var tasks = new List<Task>();
var arr = Enumerable.Range(0, 921600).ToArray();
tasks.Add(Task.Factory.StartNew(() =>
{
for (int i = 0; i < 921600 / 2; i++)
{
if (arr[i] > 240) counter++;
}
}));
tasks.Add(Task.Factory.StartNew(() =>
{
for (int j = 921600 / 2; j < 921600; j++)
{
if (arr[j] > 240) counter++;
}
}));
Task.WaitAll(tasks.ToArray());
Do not use this code! You will encounter a race condition with incrementing the integer where one thread's increment is lost due to a Read, Read, Write, Write situation. Running this in LinqPad, I ended up with counter being anything between 600000 and 800000. Obviously that range is nowhere near the actual value.
The solution to this race condition is to introduce a lock that means that only one thread can touch the variable at any one time. This negates the ability for the assignment to be multithreaded but allows us to get the correct answer. (This takes 0.042s on my machine for reference)
int counter = 0;
var tasks = new List<Task>();
var arr = Enumerable.Range(0, 921600).ToArray();
var locker = new Object();
tasks.Add(Task.Factory.StartNew(() =>
{
for (int i = 0; i < 921600 / 2; i++)
{
if (arr[i] > 240)
lock (locker)
counter++;
}
}));
tasks.Add(Task.Factory.StartNew(() =>
{
for (int j = 921600 / 2; j < 921600; j++)
{
if (arr[j] > 240)
lock (locker)
counter++;
}
}));
Task.WaitAll(tasks.ToArray());
The solution is indeed to use Parallel Linq as Dmitry has suggested:
Enumerable.Range(0, 921600).AsParallel().Count(x=>x>240);
This takes 0.031s which is quicker than our locking code and still returns the correct answer but removing the AsParallel call makes it run in 0.024s. Running a piece of code in parallel introduces a overhead to manage the threads. Sometimes the performance improvement outweighs this but a surprisingly large amount of the time it doesn't.
The moral of the story is to always run some metrics/timings of your expected data against your implementation of any code to check whether there is actually a performance benefit.
while googling for parallel concepts, came across your query. Might be the below little trick might help you
int n=921600/2;
for(int i=0; i<n; i++)
{
if(arr[i]>240) counter ++;
if(arr[n + i] > 240) counter ++;
}
I try to implement the Cannon's algorithm of matrix multiplication.
I read description on the wikipedia that provides next pseudocode:
row i of matrix a is circularly shifted by i elements to the left.
col j of matrix b is circularly shifted by j elements up.
Repeat n times:
p[i][j] multiplies its two entries and adds to running total.
circular shift each row of a 1 element left
circular shift each col of b 1 element up
and I implemented it on the C# next way:
public static void ShiftLeft(int[][] matrix, int i, int count)
{
int ind = 0;
while (ind < count)
{
int temp = matrix[i][0];
int indl = matrix[i].Length - 1;
for (int j = 0; j < indl; j++)
matrix[i][j] = matrix[i][j + 1];
matrix[i][indl] = temp;
ind++;
}
}
public static void ShiftUp(int[][] matrix, int j, int count)
{
int ind = 0;
while (ind < count)
{
int temp = matrix[0][j];
int indl = matrix.Length - 1;
for (int i = 0; i < indl; i++)
matrix[i][j] = matrix[i + 1][j];
matrix[indl][j] = temp;
ind++;
}
}
public static int[][] Cannon(int[][] A, int[][] B)
{
int[][] C = new int[A.Length][];
for (int i = 0; i < C.Length; i++)
C[i] = new int[A.Length];
for (int i = 0; i < A.Length; i++)
ShiftLeft(A, i, i);
for (int i = 0; i < B.Length; i++)
ShiftUp(B, i, i);
for (int k = 0; k < A.Length; k++)
{
for (int i = 0; i < A.Length; i++)
{
for (int j = 0; j < B.Length; j++)
{
var m = (i + j + k) % A.Length;
C[i][j] += A[i][m] * B[m][j];
ShiftLeft(A, i, 1);
ShiftUp(B, j, 1);
}
}
};
return C;
}
this code return correct result, but do it very slowly. Much slowly even than naive algorithm of matrix multiplication.
For matrix 200x200 I got that result:
00:00:00.0490432 //naive algorithm
00:00:07.1397479 //Cannon's algorithm
What I am doing wrong?
Edit
Thanks SergeySlepov, it was bad attempt to do it parallel. When I back to sequential implementation I got next result:
Count Naive Cannon's
200 00:00:00.0492098 00:00:08.0465076
250 00:00:00.0908136 00:00:22.3891375
300 00:00:00.1477764 00:00:58.0640621
350 00:00:00.2639114 00:01:51.5545524
400 00:00:00.4323984 00:04:50.7260942
okay, it's not a parallel implementation, but how can I do it correctly?
Cannon's algorithm was built for a 'Distributed Memory Machine' (a grid of processors, each with its own memory). This is very different to the hardware you're running it on (a few processors with shared memory) and that is why you're not seeing any increase in performance.
The 'circular shifts' in the pseudocode that you quoted actually mimic data transfers between processors. After the initial matrix 'skewing', each processor in the grid keeps track of three numbers (a, b and c) and executes pseudocode similar to this:
c += a * b;
pass 'a' to the processor to your left (wrapping around)
pass 'b' to the processor to 'above' you (wrapping around)
wait for the next iteration of k
We could mimic this behaviour on a PC using NxN threads but the overhead of context switching (or spawning Tasks) would kill all the joy. To make the most of a PC's 4 (or so) CPUs we could make the loop over i parallel. The loop over k needs to be sequential (unlike your solution), otherwise you might face racing conditions as each iteration of k modifies the matrices A, B and C. In a 'distributed memory machine' race conditions are not a problem as processors do not share any memory.
I'm new to threading and parallelism. I have this method for a game in C# and need to use parallel iteration. How could I use this on the for loops in the below method?
public int[,] GetLegalMoves()
{
int[,] legalMoves = new int[8, 8];
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
if (IsMoveLegal(i, j)) legalMoves[i, j] = 1;
else legalMoves[i, j] = 0;
return legalMoves;
}
This could be parallelized by parallelizing your outer loop:
public int[,] GetLegalMoves()
{
int[,] legalMoves = new int[8, 8];
Parallel.For(0, 8, i =>
{
for (int j = 0; j < 8; j++)
if (IsMoveLegal(i, j)) legalMoves[i, j] = 1;
else legalMoves[i, j] = 0;
});
return legalMoves;
}
That being said, this will likely cause this to run slower, as an 8x8 matrix is such a small value that the overhead of scheduling the parallel work is likely higher than the gains made, unless IsMoveLegal is a fairly expensive operation.
This will also require that IsMoveLegal be safe to use from multiple threads.