Running a large number of tasks - c#

I want to create a large number of tasks n and use in each task i the result I got from task i-1.
I came up with:
class TaskTest
{
static int count;
public static void Main()
{
int n = 1000000;
var t = Add(n);
var sum = t.GetAwaiter().GetResult();
Console.WriteLine("sum is: " + sum);
}
public static Task<int> Add(int step)
{
Task t = new Task(() => Add(step));
t.Start();
if (step == 0)
return Task.FromResult(0);
return Task.FromResult(Add(step - 1).Result + 1);
}
static void AddWithLock(int step)
{
if (step == 0)
return;
Interlocked.Increment(ref count);
var t = Task.Factory.StartNew(state => AddWithLock(step - 1), CancellationToken.None);
t.Wait();
}
}
Using the method Add() works for a small value of n like 1000, but fails with a StackOwerFlowException for n = 1 000 000.
Usin AddWithLock() is not exactly what I want (it does not use the results from other tasks) and while it works for large numbers it is incredibly slow.
So how can I modify the code that it works for numbers such as n = 1 million?
edit:
I tried using TaskCompletionSource but still get StackOverflowException.
public static Task<int> Add2(int step)
{
var tcs = new TaskCompletionSource<int>();
if (step == 0)
tcs.SetResult(0);
else
{
var r = Add2(step - 1).Result;
tcs.SetResult(r + 1);
}
return tcs.Task;
}

Without using recursion it works good enough. It completes in around 1000 miliseconds on my PC (old i7). No stack exploding.
using System;
using System.Diagnostics;
using System.Threading.Tasks;
namespace ManyTasks
{
class Program
{
public static void Main()
{
int n = 1000000;
Task<int>[] tasks = new Task<int>[n];
var sw = new Stopwatch();
sw.Start();
Task.Factory.StartNew(() =>
{
for (int i = 0; i < n; i++)
{
int j = i;
tasks[i] = new Task<int>(() =>
{
if (j == 0)
return 1;
var result = tasks[j - 1].Result + 1;
return result;
});
tasks[i].Start();
tasks[i].Wait();
}
}).Wait();
sw.Stop();
Console.WriteLine(tasks[n - 1].Result);
Console.WriteLine($"time: {sw.Elapsed.TotalMilliseconds:0.000}ms");
}
}
}

Related

Cannot understand the behaviour of the threads C#

static void Main(string[] args)
{
var sw = new Stopwatch();
sw.Start();
int noOfThreads = Environment.ProcessorCount;
//int minVal = 1;
int maxVal = 10000000;
int blockSize = maxVal / noOfThreads;
List<Thread> threads = new List<Thread>();
List<List<int>> results = new List<List<int>>();
object thisLock = new object();
for (int i = 0; i < noOfThreads; ++i)
{
lock(thisLock)
{
Thread th = new Thread(() =>
{
results.Add(GetPrimeNumbers(i * blockSize, i * blockSize + blockSize));
});
th.Start();
threads.Add(th);
}
}
foreach (var elem in threads)
elem.Join();
}
private static List<int> GetPrimeNumbers(int low, int high)
{
List<int> result = new List<int>();
//Debug.WriteLine("Low: {0}. High: {1}", low, high);
for(int i = low; i <= high; ++i)
{
if (IsPrime(i))
result.Add(i);
}
return result;
}
static bool IsPrime(int number)
{
if (number % 2 == 0)
return false;
else
{
var topLimit = (int)Math.Sqrt(number);
for (int i = 3; i <= topLimit; i += 2)
if (number % i == 0)
return false;
return true;
}
}
With the above code, I was expecting that when I put breakpoint in the GetPrimeNumbers(int low, int high) I would see range of values for low and high, e.g: (0, 1250000), (1250000, 2500000).....(8750000, 10000000). But what I observing is that there are certain blocks that gets passed multiple times - (2500000, 3750000) while certain do not passed at all -(0, 1250000) and this behaviour also matches the results I am getting.
I am curious why I am seeing this behaviour. Is there a way to prevent this?
I am aware of the fact that I can use Parallel.For() and over here I do see the expected behaviour at breakpoint in GetPrimes(int low, int high). But as I mentioned before I am curious why I am seeing the former behaviour.
Thanks in advance!
The problem is that a for loop reuses the same i variable across iterations, and your thread delegate is closing over that variable.
There are various ways to fix this. A simple one is to use a new variable declared within your loop:
for (int i = 0; i < noOfThreads; ++i)
{
int j = i; // capture the value
lock(thisLock)
{
Thread th = new Thread(() =>
{
results.Add(GetPrimeNumbers(j * blockSize, j * blockSize + blockSize));
});
th.Start();
threads.Add(th);
}
}
This still has other issues, though. I'd recommend something more like this:
var allPrimeNumbers = Enumerable.Range(0, numberOfThreads)
.AsParallel()
.SelectMany(i => GetPrimeNumbers(i * blockSize, i * blockSize + blockSize))
.ToList();
Further Reading
Is there a reason for C#'s reuse of the variable in a foreach?
StriplingWarrior had it close, but as mentioned in the comments, you still have a threading bug. You need to move the lock inside the Thread action. Also, to get the best performance, hold the lock for the shortest amount of time possible, which is when modifying the shared results variable. To do that I separated the GetPrimeNumbers call from the results.Add call.
for (int i = 0; i < noOfThreads; ++i)
{
int j = i; // capture the value
Thread th = new Thread(() =>
{
result = GetPrimeNumbers(j * blockSize, j * blockSize + blockSize);
lock(thisLock)
{
results.Add(result);
}
});
th.Start();
threads.Add(th);
}
Also, unless you really need to manage your own threads I would recommend using Tasks (TPL) instead. Here is a modification using Tasks
Task<List<int>> tasks = new Task<List<int>>();
for (int i = 0; i < noOfThreads; ++i)
{
int j = i; // capture the value
tasks.Add(Task.Run(() => GetPrimeNumbers(j * blockSize, j * blockSize + blockSize)));
}
Task.WaitAll(tasks);
results = tasks.Select(t => t.Result).ToList();

Need to limit every odd or even thread with a semaphore c#

so I'm in a bit confused as to how I'm supposed to do something. I've got 5 threads that are doing a basic task and they are generated with a for loop in main. I've already used a semaphore that limits the amount of threads running at a time as that's a part of the exercise, what I've got left is to make sure that threads that are next to each other (they're numbered 0-4 using the loop) don't run simultaneously. What I've got as an idea is to block every odd or even thread(it doesn't really matter) but I can't figure out how to both let two threads in and at the same time block every odd one. Is there a specific method for that, or maybe if there is another way, like letting three in at first and somehow not letting the second one in but letting the third one. I'll leave what I've got done so far:
edit: For clarification the way it has to be thought about is actually a bit different then what I initially asked about. So if 1 is running both 0 and 2 aren't allowed to run. But if 0 is running both 4 and 1 aren't allowed to run either. I'm pretty sure that it's obvious that if 4 is running 0 and 3 aren't allowed to work etc. .
using System.Threading;
namespace StudentProblem
{
public class StudentProblem
{
static Semaphore stop = new Semaphore(2,2);
static Semaphore gate = new Semaphore(3,3);
public static void Student(Object o)
{
var r = new Random();
var num = (int) o;
while (true)
{
Console.WriteLine(" Student " + num + " start learning.");
Thread.Sleep(r.Next(2000, 3000));
for (int i = 0; i < num; i++)
Console.Write("_");
//gate.WaitOne();
stop.WaitOne();
Console.WriteLine("> Student " + num + " start eating.");
Thread.Sleep(r.Next(2000, 3000));
for (int i = 0; i < num; i++)
Console.Write("_");
Console.WriteLine("< Student " + num + " stop eating");
//gate.Release();
stop.Release();
}
}
}
class Program
{
static void Main(string[] args)
{
var studentThreads = new Thread[5];
for (int i = 0; i < 5; i++)
{
studentThreads[i] = new Thread(StudentProblem.Student);
studentThreads[i].Start(i);
}
}
}
}
In the end I decided to ditch the whole multiple semaphore approach and went with the old and trusty way. I'll add my solution here. It's not that great, but it works.
using System;
using System.Collections.Generic;
using System.Threading;
namespace testing
{
public class StudentProblem
{
public static List<StudentProblem> allProblems = new List<StudentProblem>();
static Semaphore eatingGate = new Semaphore(2, 2);
private object id;
private bool eating = false;
public StudentProblem(object o)
{
id = o;
}
public object Id
{
get
{
return this.id;
}
}
public bool Eating
{
get
{
return this.eating;
}
}
public void DoStuff()
{
var r = new Random();
var num = (int)this.Id;
Console.WriteLine(" Student " + num + " start learning.");
Thread.Sleep(r.Next(2000, 3000));
while (true)
{
for (int i = 0; i < num; i++)
Console.Write("_");
int indexBehind = 0;
int indexFront = 0;
for (int i = 0; i < allProblems.Count; i++)
{
if(num == 0)
{
indexBehind = 4;
}
else
{
indexBehind = num - 1;
}
if(num == 4)
{
indexFront = 0;
}
else
{
indexFront = num + 1;
}
check:
if (allProblems[indexBehind].Eating != true && allProblems[indexFront].Eating != true)
{
if (eatingGate.WaitOne())
{
this.eating = true;
Thread.Sleep(250);//poigrai si s timeout-a
Console.WriteLine("> Student " + num + " start eating.");
Thread.Sleep(r.Next(1000, 2000));
for (int j = 0; j < num; j++)
Console.Write("_");
Console.WriteLine("< Student " + num + " stop eating");
this.eating = false;
eatingGate.Release();
Console.WriteLine(" Student " + num + " start learning.");
Thread.Sleep(r.Next(2000, 3000));
}
else
{
goto check;
}
}
else
{
goto check;
}
}
}
}
}
class Program
{
static void Main(string[] args)
{
var studentThreads = new Thread[5];
for (int i = 0; i < 5; i++)
{
StudentProblem.allProblems.Add(new StudentProblem(i));
studentThreads[i] = new Thread(StudentProblem.allProblems[i].DoStuff);
studentThreads[i].Start();
}
}
}
}

Share method between threads

I have a Func like this:
int loopMax = 10, taskMax = 10;
int executionCounter = 0;
Func<int> calculator = new Func<int>(() =>
{
executionCounter++;
int result = 0;
for (int i = 0; i < loopMax; i++)
{
Thread.Sleep(100);
if (result + i >= int.MaxValue)
result = 0;
result += i;
}
return result;
});
Which could be called by multiple threads. For example like this:
Task[] tasks = new Task[taskMax];
for (int i = 0; i < taskMax; i++)
{
tasks[i] = Task.Run(() => _=calculator());
}
Task.WaitAll(tasks);
I need to share the calculator function across all threads, and makes this function being called only once. In fact the executionCounter variable's value after running this code should remain 1, and all of the threads should have the same return value.
UPDATE 1
I think I can solve it if I find a way to server the first thread and block every other threads and after completion of first thread's method call, signal the methods result to other threads and also cancel them, to prevent them calling calculator again.
Using lock inside the method also is not what I am looking for, because in that case again the calculator is being called multiple times...
It seems that you need the Lazy<T> class. This class provides support for lazy initialization. Here is how you could use it:
Lazy<int> lazyCalculator = new Lazy<int>(calculator);
Task[] tasks = new Task[taskMax];
for (int i = 0; i < taskMax; i++)
{
tasks[i] = Task.Run(() => _ = lazyCalculator.Value);
}
Task.WaitAll(tasks);
When a Lazy instance is constructed, it can take an optional LazyThreadSafetyMode argument. The default value of this argument is ExecutionAndPublication, with the behavior described below:
Locks are used to ensure that only a single thread can initialize a Lazy<T> instance in a thread-safe manner.
It looks like you want is that your Calculator method can be executed by any thread, but this method should be executed only once. If it is true, then we would use lock statement.
The purpose of lock statement is:
The lock statement acquires the mutual-exclusion lock for a given
object, executes a statement block, and then releases the lock
An example:
static object lockCalculatorMethod = new object();
static int executionCounter = 0;
static int loopMax = 10;
static int taskMax = 10;
static void Main(string[] args)
{
Task[] tasks = new Task[taskMax];
for (int i = 0; i < taskMax; i++)
{
tasks[i] = Task.Run(() => _ = Calculator());
}
Task.WhenAll(tasks);
}
and Calculator method:
static int Calculator()
{
lock (lockCalculatorMethod)
{
if (executionCounter < 1)
{
executionCounter++;
int result = 0;
for (int i = 0; i < loopMax; i++)
{
Thread.Sleep(100);
if (result + i >= int.MaxValue)
{
result = 0;
result += i;
}
}
return result;
}
else
return -1;
}
}
UPDATE:
If you want to cache result and avoid recalculation while calling by other threads, then you can use threadSafe collection ConcurrentQueue<T> and just get items from this collection:
static object lockCalculatorMethod = new object();
static ConcurrentQueue<int> queue = new ConcurrentQueue<int>();
static int executionCounter = 0;
static int loopMax = 7;
static int taskMax = 7;
static void Main(string[] args)
{
Task[] tasks = new Task[taskMax];
for (int i = 0; i < taskMax; i++)
{
tasks[i] = Task.Run(() =>
{
var result = Calculator();
Console.WriteLine(result);
});
}
Task.WaitAll(tasks);
}
And Calculator method:
static int Calculator()
{
int result = 0;
lock (lockCalculatorMethod)
{
int lockResult = 0;
if (executionCounter < 1)
{
executionCounter++;
for (int i = 0; i < loopMax; i++)
{
Thread.Sleep(100);
lockResult += i;
}
queue.Enqueue(lockResult);
}
}
queue.TryPeek(out result);
return result;
}

How to measure total execution time of a parallel task or multi-thread program in c#?

I am a novice in C#/.NET. Here I am trying to run the following parallel tasks and measure the total execution time.
But after running the code the execution time is showing just > 6 ms which is way less than it is supposed to be. I am not sure if there is any misplacing of the Stopwatch() function that's giving this unexpected result.
Your help will be appreciated :
namespace Tests
{
class Prod
{
static void Main(string[] args)
{
Stopwatch s = new Stopwatch();
s.Start();
{
Task T1 = Task.Run(() =>
{
for (int i = 0; i <= 5000; i++)
Console.WriteLine("Test1:" + i);
});
Task T2 = Task.Run(() =>
{
for (int i = 0; i <= 5000; i++)
Console.WriteLine("Test2:" + i);
});
Task T3 = Task.Run(() =>
{
for (int i = 0; i <= 5000; i++)
Console.WriteLine("Test3:" + i);
});
}
s.Stop();
Console.WriteLine("Press any key to quit");
Console.ReadKey();
Console.WriteLine("Total Task Ellapsed time -> {0}", s.ElapsedMilliseconds);
}
}
}
You need a Task.WaitAll before the stop of the Stopwatch (s.Stop() in your code)
for example:
Task.WaitAll(T1,T2,T3);
s.Stop();
One solution would be to wait for all Tasks to be completed using Task.WaitAll
Task.WaitAll(T1,T2,T3);
Complete Code
Stopwatch s = new Stopwatch();
s.Start();
{
Task T1 = Task.Run(() =>
{
for (int i = 0; i <= 5000; i++)
Console.WriteLine("Test1:" + i);
});
Task T2 = Task.Run(() =>
{
for (int i = 0; i <= 5000; i++)
Console.WriteLine("Test2:" + i);
});
Task T3 = Task.Run(() =>
{
for (int i = 0; i <= 5000; i++)
Console.WriteLine("Test3:" + i);
});
Task.WaitAll(T1,T2,T3); // Change here
}
s.Stop();
Console.WriteLine("Press any key to quit");
Console.WriteLine("Total Task Ellapsed time -> {0}", s.ElapsedMilliseconds);

CountdownEvent not waiting for all threads to signal

I've got the following multithreaded code for calculating Euler's number. I'm new in multithreaded programming and maybe I'm missing something. For some reason countdown.Wait() is not waiting for all the threads and totalSum is different almost every time. It looks like it skips some of the intermediate sums.
public static class Program
{
private static int elementsCount = 500;
private static int threadsCount = 20;
private static string outputFileName = "defaultFileName.txt";
private static bool isInQuietMode = false;
private static BigRational totalSum = new BigRational(0.0m);
private static CountdownEvent countDown = new CountdownEvent(threadsCount);
private static Object locker = new Object();
private static void Main(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int threadIndex = 0; threadIndex < threadsCount; threadIndex++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(CalculateEulerNumber), threadIndex);
}
countDown.Wait();
File.WriteAllText(outputFileName, "Euler's number: " + totalSum);
stopwatch.Stop();
Console.WriteLine("Result: ");
Console.WriteLine("Total time elapsed - " + stopwatch.Elapsed);
if (!isInQuietMode)
{
Console.WriteLine("Euler's number - " + totalSum);
}
}
private static void CalculateEulerNumber(object threadIndexObject)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int threadIndex = Convert.ToInt32(threadIndexObject);
BigRational sum = new BigRational(0.0m);
for (int k = threadIndex; k < elementsCount; k += threadsCount)
{
BigRational numerator = BigRational.Pow((3 * k), 2) + 1;
BigRational denominator = Factorial(3 * k);
sum += BigRational.Divide(numerator, denominator);
}
totalSum = BigRational.Add(totalSum, sum);
stopwatch.Stop();
lock (locker)
{
int threadNumber = threadIndex + 1;
Console.WriteLine("Тhread " + threadNumber + ": ");
Console.WriteLine("Time elapsed - " + stopwatch.Elapsed);
if (!isInQuietMode)
{
Console.WriteLine("Intermediate sum - " + sum.ToDecimalString(40));
}
Console.WriteLine();
}
countDown.Signal();
}
private static BigRational Factorial(int n)
{
BigRational factorial = 1;
for (int i = 1; i <= n; i++)
{
factorial *= i;
}
return factorial;
}
}
#usr made a good point: you better use ConcurrentStack<T> or ConcurrentQueue<T> as detailed in http://msdn.microsoft.com/en-us/library/system.collections.concurrent%28v=vs.110%29.aspx.
Also, it's better to implement your algorithm using Task.Factory as explained by Alexandra Rusina in http://blogs.msdn.com/b/csharpfaq/archive/2010/06/01/parallel-programming-in-net-framework-4-getting-started.aspx. As per the mentioned resources, your solution may look like something following (giving you general idea)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
ConcurrentStack<int> cs = new ConcurrentStack<int>();
public static double YourFunction(int SomeNumber)
{
// computation of result
return result;
}
private void start_Click(object sender, RoutedEventArgs e)
{
textBlock1.Text = "";
label1.Content = "Milliseconds: ";
var watch = Stopwatch.StartNew();
List<Task> tasks = new List<Task>();
for (int i = 2; i < 20; i++)
{
int j = i;
var t = Task.Factory.StartNew(() =>
{
int result = YourFunctiopn(j);
this.Dispatcher.BeginInvoke(new Action(() =>
cs.Add(result ))
, null);
});
tasks.Add(t);
}
Task.Factory.ContinueWhenAll(tasks.ToArray(),
result =>
{
var time = watch.ElapsedMilliseconds;
this.Dispatcher.BeginInvoke(new Action(() =>
label1.Content += time.ToString()));
});
}
}
Hope this will help. Rgds,
You are using the CountDownEvent wrongly.CountDownEvent are for signalling and you dont need this in current program. You can do this with tasks:
public class Class1
{
private static int elementsCount = 500;
private static int threadsCount = 20;
private static string outputFileName = "defaultFileName.txt";
private static bool isInQuietMode = false;
private static BigRational totalSum = new BigRational(0.0m);
public static void Main1(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
List<Task<BigRational>> tasks = new List<Task<BigRational>>();
//Create the tasks
for (int threadIndex = 0; threadIndex < threadsCount; threadIndex++)
{
Task<BigRational> task = new Task<BigRational>((data)=>
{
return CalculateEulerNumber(data);
},threadIndex);
tasks.Add(task);
}
foreach (var task in tasks)
{
task.Start();
}
//Wait for tasks
Task.WaitAll(tasks.ToArray());
//Add the results
foreach (var task in tasks)
{
totalSum = BigRational.Add(totalSum, task.Result);
}
File.WriteAllText(outputFileName, "Euler's number: " + totalSum);
stopwatch.Stop();
Console.WriteLine("Result: ");
Console.WriteLine("Total time elapsed - " + stopwatch.Elapsed);
if (!isInQuietMode)
{
Console.WriteLine("Euler's number - " + totalSum);
}
}
private static BigRational CalculateEulerNumber(object threadIndexObject)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int threadIndex = Convert.ToInt32(threadIndexObject);
BigRational sum = new BigRational(0.0m);
for (int k = threadIndex; k < elementsCount; k += threadsCount)
{
BigRational numerator = BigRational.Pow((3 * k), 2) + 1;
BigRational denominator = Factorial(3 * k);
sum += BigRational.Divide(numerator, denominator);
}
stopwatch.Stop();
int threadNumber = threadIndex + 1;
Console.WriteLine("Тhread " + threadNumber + ": ");
Console.WriteLine("Time elapsed - " + stopwatch.Elapsed);
if (!isInQuietMode)
{
Console.WriteLine("Intermediate sum - " + sum.ToString());
}
Console.WriteLine();
return sum;
}
private static BigRational Factorial(int n)
{
BigRational factorial = 1;
for (int i = 1; i <= n; i++)
{
factorial *= i;
}
return factorial;
}
}
So create the task and each task can run seperately and return individual sum. You can then add the results to create the total sum. There is no need of locks either.

Categories

Resources