I'm trying to get the CPU% for all processes in parallel using C#'s TPL. The code that I have is:
private IDictionary<Process, int> _usage = new Dictionary<Process, int>();
public ProcessCpuUsageGetter()
{
Process[] processes = Process.GetProcesses();
int processCount = processes.Count();
Task[] tasks = new Task[processCount];
int counter = 0;
for (int i = 0; i < processCount; i++)
{
tasks[i] = Task.Factory.StartNew(() => DoWork(processes[i]));
}
Task.WaitAll(tasks);
}
private void DoWork(object o)
{
Process process = (Process)o;
PerformanceCounter pc = new PerformanceCounter("Process", "% Processor Time", process.ProcessName, true);
pc.NextValue();
Thread.Sleep(1000);
int cpuPercent = (int)pc.NextValue() / Environment.ProcessorCount;
_usage.Add(process, cpuPercent);
}
But it fails with An item with the same key has already been added. Any ideas on what I'm doing wrong?
The problem is the closure of the local variable i when passed to the expression for starting the task. This causes current value of i used by the DoWork(processes[i]) even when i being modified by the for.
Create a local variable:
for (int i = 0; i < processCount; i++)
{
int localI = i;
tasks[i] = Task.Factory.StartNew(() => DoWork(processes[localI]));
}
Related
I'm creating an UWP application that needs to measure the time the user is looking at an object. This application has around 300 objects to measure the time of. To do this we will be using around 300 timers. To achieve this we will have to create 300 stopwatches individually which is highly inefficient.
The timer starts when the user is looking at the corresponding object and stops when the user is no longer looking at the corresponding object. If the user's gaze is fixated on the corresponding object again the timer of course starts again. At the end all of the times of the stopwatches will be saved into a file. Creating 300 stopwatches requires a new line of code for every stopwatch which does not seem very efficient. I have tried to automate the stopwatch creation process by using Enumerable.range but so far i have not been able to find a solution.
/// <summary>
/// All stopwatches for every word. In our real code we will have around 300 stopwatches.
/// </summary>
Stopwatch Stopwatch1 = new Stopwatch();
Stopwatch Stopwatch2 = new Stopwatch();
Stopwatch Stopwatch3 = new Stopwatch();
Stopwatch Stopwatch4 = new Stopwatch();
Stopwatch Stopwatch5 = new Stopwatch();
Stopwatch Stopwatch6 = new Stopwatch();
Stopwatch Stopwatch7 = new Stopwatch();
Stopwatch Stopwatch8 = new Stopwatch();
Stopwatch Stopwatch9 = new Stopwatch();
Stopwatch Stopwatch10 = new Stopwatch();
So, at first you need to get a list of the available objects. You can use the following code to create a generic dictionary that keeps a stopwatch for every object you have. There is also a sample implementation of a method that generates a gazing survey.
You still have to add the code that calls the start and stop methods.
class Program
{
static Dictionary<object, Stopwatch> stopwatchesByObject;
static void Main(string[] args)
{
List<object> objects = new List<object>();
// now you have to fill the objects list...
stopwatchesByObject = new Dictionary<object, Stopwatch>();
foreach (var o in objects)
{
stopwatchesByObject.Add(o, new Stopwatch());
}
}
// Call this method when the user starts gazing at object o
static void StartGazingAt(object o)
{
stopwatchesByObject[o].Start();
}
// Call this method when the user stops gazing at object o
static void StopGazingAt(object o)
{
stopwatchesByObject[o].Stop();
}
static void CreateStatistics()
{
StringBuilder sb = new StringBuilder();
foreach (var entry in stopwatchesByObject)
{
sb.AppendLine($"Gazed at {entry.Key.ToString()} for {entry.Value.Elapsed.TotalSeconds} seconds.");
}
File.WriteAllText("c:\\temp\\statictics.txt", sb.ToString());
}
}
I liked Stefan Illners approach and wanted to add some linq-magic, which, imo, is really neat and good readable.
using System.Linq;
var myListOfItemsToWatch = new List<object> { "foo", "bar", "baz" };
var listOfStopwatches = myListOfItemsToWatch.ToDictionary(watchItem =>
watchItem, i => new Stopwatch()
);
Just only define List<Stopwatch>()
var l = new List<Stopwatch>();
for (var i = 0; i < 300; i++)
{
var w = Stopwatch.StartNew();
w.Stop();
l.Add(w);
}
To show you how to deal with it see this example
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
public static List<Stopwatch> sws = new List<Stopwatch>();
public static List<Thread> threads = new List<Thread>();
static void Main()
{
for (var i = 0; i < 300; i++)
{
threads.Add(new Thread(Dummy));
sws.Add(new Stopwatch());
}
for(int i = 0; i < 300; i++) sws[i].Start();
new Thread( () => { for(int i = 0; i < 5; i++) threads[i].Start(i); }).Start();
new Thread( () => { for(int i = 5; i < 10; i++) threads[i].Start(i); }).Start();
new Thread( () => { for(int i = 10; i < 15; i++) threads[i].Start(i); }).Start();
new Thread( () => { for(int i = 15; i < 20; i++) threads[i].Start(i); }).Start();
new Thread( () => { for(int i = 20; i < 25; i++) threads[i].Start(i); }).Start();
new Thread( () => { for(int i = 25; i < 30; i++) threads[i].Start(i); }).Start();
new Thread( () => { for(int i = 30; i < 35; i++) threads[i].Start(i); }).Start();
new Thread( () => { for(int i = 35; i < 40; i++) threads[i].Start(i); }).Start();
Console.Read();
}
static void Dummy(object data)
{
int i = (int)data;
Thread.Sleep(250);
sws[i].Stop();
Console.WriteLine(sws[i].ElapsedMilliseconds.ToString());
}
}
}
I want to create a multithreaded application code. I want to execute configured no of threads and each thread do the work. I want to know is this the write approach or do we have better approach. All the threads needs to be executed asynchronously.
public static bool keepThreadsAlive = false;
static void Main(string[] args)
{
Program pgm = new Program();
int noOfThreads = 4;
keepThreadsAlive = true;
for (int i = 1; i <= noOfThreads; i++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), (object)i);
}
System.Console.ReadLine();
StopAllThreads();
System.Console.ReadLine();
}
private static void DoWork(object threadNumber)
{
int threadNum = (int)threadNumber;
int counter = 1;
while (keepThreadsAlive)
{
counter = ProcessACK(threadNum, counter);
}
}
private static int ProcessACK(int threadNum, int counter)
{
System.Console.WriteLine("Thread {0} count {1}", threadNum, counter++);
Random ran = new Random();
int randomNumber = ran.Next(5000, 100000);
for (int i = 0; i < randomNumber; i++) ;
Thread.Sleep(2000);
return counter;
}
As others have pointed out, the methods you are using are dated and not as elegant as the more modern C# approach to accomplishing the same tasks.
Have a look at System.Threading.Tasks for an overview of what is available to you these days. There is even a way to set the maximum threads used in a parallel operation. Here is a simple (pseudocode) example:
Parallel.ForEach(someListOfItems, new ParallelOptions { MaxDegreeOfParallelism = 8 }, item =>
{
//do stuff for each item in "someListOfItems" using a maximum of 8 threads.
});
Hope this helps.
I was experimenting with tasks. Why does this output 10 and not each value of the loop?
public static void StartTasks()
{
Task[] tasks = new Task[10];
for (int i = 0; i < 10; i++)
tasks[i] = new Task(() => Console.WriteLine(i));
foreach (Task task in tasks)
{
task.Start();
}
}
C# lambdas capture a reference to the variable, not the value of the variable.
If you want to capture the value, you need to make a copy of it first inside the loop which causes the capture to get the reference to the locally scoped unchanging variable.
public static void StartTasks()
{
Task[] tasks = new Task[10];
for (int i = 0; i < 10; i++) {
int j = i;
tasks[i] = new Task(() => Console.WriteLine(j));
}
foreach (Task task in tasks)
{
task.Start();
}
}
In addition to the accepted answer, you can also pass a parameter to the task. For example,
using System;
using System.Threading.Tasks;
static void StartTasks(int instances)
{
var tasks = new Task[instances];
for (int i = 0; i < instances; i++)
{
tasks[i] = new Task((object param) =>
{
var t = (int)param;
Console.Write("({0})", t);
}, i);
}
Parallel.ForEach<Task>(tasks, (t) => { t.Start(); });
Task.WaitAll(tasks);
}
I often get strange resulst when passing int variables to tasks such as in this example:
List<List<object>> ListToProcess = new List<List<object>>();
// place some lists in list to process
foreach (var temp in Foo)
ListToProcess.Add(temp);
foreach (var tempArray in ListToProcess)
{
// initialize each list in ListToProcess
}
int numberOfChunks = ListToProcess.Count;
Task[] tasks = new Task[numberOfChunks];
for (int counter = 0; counter < numberOfChunks; counter++)
{
tasks[counter] = Task.Factory.StartNew(() =>
{
// counter is always = 5 why? <---------------------------
var t = ListToProcess[counter];
});
}
How can I solve this problem?
This is known as a closure. You are not using the value of the variable, you are using the variable itself. When the code executes, it uses the value at the time of execution, not the value when the Task was defined.
To fix this issue, I believe you would do something like this:
for (int counter = 0; counter < numberOfChunks; counter++)
{
int cur = counter;
tasks[counter] = Task.Factory.StartNew(() =>
{
// counter is always = 5 why? <---------------------------
var t = ListToProcess[cur];
});
}
There is no guarantee as to when the 'counter' variable in the Action block of StartNew will be accessed. What is likely to happen is that all 5 values are looped through, and the tasks are created, then the tasks are scheduled to run.
When they do run, the following is executed:
var t = ListToProcess[counter];
But at this stage count is already equal to 5.
Perhaps you should look at parallel collections?
ListToProcess.AsParallel().ForAll(list => dosomething(list));
There are many other options around this area.
for (int counter = 0; counter < numberOfChunks; counter++)
{
var referenceVariable = new{val=counter};
tasks[counter] = Task.Factory.StartNew(() =>
{
var t = ListToProcess[referenceVariable.val];
});
}
Since variables are captured, you can solve this by redeclaring a new variable in each loop.
for (int counter = 0; counter < numberOfChunks; counter++)
{
int localCounter = counter;
tasks[localCounter] = Task.Factory.StartNew(() =>
{
// counter is always = 5 why? <---------------------------
var t = ListToProcess[localCounter];
});
}
In below sample code, I use lambda function to make 3 threads doing different things. My goal is make the thread count configurable, so I was thinking using a loop to start threads. But I always got in static function can't call non-static members error. Can the community help me or direct me to a tutorial? Thanks a lot!
My Code:
internal class FeedClient
{
private static void Main(string[] args)
{
int iteration = 10;
int ranSleepTime = 1000;
var obj = new MyClass();
var threads = new Thread[3];
(threads[0] = new Thread(() =>
{
Random random = new System.Random();
for (int i = 0; i < iteration; i++)
{
obj.MyMethod("my string 1");
Thread.Sleep(random.Next(ranSleepTime));
}
})).Start();
(threads[1] = new Thread(() =>
{
Random random = new System.Random();
for (int i = 0; i < iteration; i++)
{
obj.MyMethod("my string 2");
Thread.Sleep(random.Next(ranSleepTime));
}
})).Start();
(threads[2] = new Thread(() =>
{
Random random = new System.Random();
for (int i = 0; i < iteration; i++)
{
obj.MyMethod("my string 3");
Thread.Sleep(random.Next(ranSleepTime));
}
})).Start();
foreach (Thread thread in threads)
{
thread.Join();
}
obj.Close(false);
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
Desired look:
for(int i=0;i<3;i++){
threads[i] = new Thread(func); // func is the lambda function
threads[i].Start(myData[i]); // myData[] may be a string array
}
The error message seems to indicate that you are attempting to use an instance member from a static method somewhere. Naturally that is not allowed since a static method does not have a this reference. Here is how I would refactor your code.
public static void Main()
{
string[] myData = GetStringArray();
int iteration = 10;
int ranSleepTime = 1000;
var obj = new MyClass();
var threads = new Thread[myData.Length];
for (int i = 0; i < threads.Length; i++)
{
int captured = i; // This is required to avoid capturing the loop variable.
threads[i] = new Thread(
() =>
{
var random = new Random();
for (int i = 0; i < iteration; i++)
{
obj.MyMethod(myData[captured]);
Thread.Sleep(random.Next(ranSleepTime));
}
});
threads[i].Start();
}
foreach (Thread thread in threads)
{
thread.Join();
}
obj.Close(false);
}
I must mention, however, that creating new threads in an unbounded loop is generally undesirable. If the loop has a tight bound then maybe, but I would have to get a better understanding of the problem before making any further comments regarding this point.