I'm C# newbie.
Question:
class Program
{
static void why()
{
List<Task> listOfDummyTask = new List<Task>();
for (int i = 0; i < 100; ++i)
{
Task hoho = Task.Run(() =>
{
Thread.Sleep(2000);
Console.WriteLine("Die");
});
listOfDummyTask.Add(hoho);
}
Task.WaitAll(listOfDummyTask.ToArray());
}
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Reset();
sw.Start();
why();
sw.Stop();
Console.WriteLine("{0} ms", sw.ElapsedMilliseconds.ToString());
Console.WriteLine("----------------------------------");
sw.Reset();
sw.Start();
why();
sw.Stop();
Console.WriteLine("{0} ms", sw.ElapsedMilliseconds.ToString());
Console.WriteLine("----------------------------------");
Console.WriteLine("End");
}
}
First, I call why(), It prints "Die" same 4 times.
And It prints 1 ~ 4 "Die".
First why() stopwatch returns 28,000 ms, but when I call second why(),
It prints "Die" 8 time, And It prints 5~8 "Die" same time..
Second why() stopwatch returns 10,000 ~ 14,000 ms.
Why?
What Keyword it's situation?
Task.Run in a loop 100 times will enqueue 100 work items to the default scheduler (thread pool). If the thread pool decides to execute up to 4 items concurrently, then it will take 4 work items off the queue and complete them in roughly 2 seconds. Then it will take four more, and so on until all are done.
There's no real expectation of how many tasks will execute concurrently, and how many will be postponed.
Related
When calling Task.Run(..)..Wait(...) in a static constructor it waits for the entire timeout time even though the task has finished. Just curious why this is? What is best practice for this scenario? Test class that shows it below
static TestClass()
{
var delay = 100;
var wait = 500;
// Will wait the whole wait time
var sw = Stopwatch.StartNew();
Task.Run(() => DoStuff(delay)).Wait(wait);
sw.Stop();
var elapsedMs = sw.ElapsedMilliseconds;
Debug.WriteLine($"Elapsed {elapsedMs}");
// Will return when task is complete
sw.Restart();
Task.Run(()=>
{
var awaiter = Task.Run(() => DoStuff(delay)).GetAwaiter();
var maxMs = delay * TimeSpan.TicksPerMillisecond;
var swElapse = Stopwatch.StartNew();
while (!awaiter.IsCompleted && swElapse.ElapsedTicks < maxMs)
{ }
swElapse.Stop();
}).Wait(wait);
sw.Stop();
elapsedMs = sw.ElapsedMilliseconds;
Debug.WriteLine($"Elapsed {elapsedMs}");
}
static void DoStuff(int delay)
{
// Some async task called and waited for result
Task.Run(async () => await Task.Delay(100)).GetAwaiter().GetResult();
}
}
in a static constructor
Last time I checked, static constructors take a lock because only one of them can execute at a time. So, if the static constructor queues work to another thread that then does other things (i.e., call other static constructors) while the original static constructor is blocked on that other thread, then you can end up with a deadlock that is only resolved with the timeout.
What is best practice for this scenario?
Don't block on async code, especially not in constructors, and especially especially not in static constructors. (Link is to my blog).
var delay = 100;
var maxMs = delay * TimeSpan.TicksPerMillisecond;
var secondsTotal = maxMs / 1000.0m;
Console.WriteLine("Total seconds thread will wait: " + secondsTotal + "s.");
When you run this code, you get: 1000s. 1000 seconds is 16.7 minutes.
Your while condition is:
!awaiter.IsCompleted && swElapse.ElapsedTicks < maxMs
Because this is the "AND" operation, the while loop will continue so long as what's in the parentheses is true.
In your case the "awaiter.IsCompleted" evaluates for true, AND less than 16 minutes evaluates for true as well (until 16 minutes pass). Only until one of the conditions is false will the while loop stop repeating.
This is likely why you are experiencing this behavior.
Now a days I'm practicing some programs of C#. I have an issue in this program.
I have created this program and it took 21 seconds to execute and my CPU usage is 20% and Ram usage is 1Gb max.
static void Main(string[] args)
{
string str = Console.ReadLine();
if (str == "start")
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 1; i < 200000; i++)
{
Console.WriteLine("Acccessed Value" + i.ToString());
Console.WriteLine("Time " + sw.ElapsedMilliseconds);
}
}
Console.Read();
}
but when I create 2 instances of this It took 140 seconds and CPU usage is 20 % and Ram usage is 1GB max.
Can you please help me, how can I run multiple instances which will take 21 seconds but can utilize my Ram and CPU as maximum.
You don't want to start different instances. Try using Tasks in your application, to utilize multiple cores of your CPU. Create Environment.ProcessorCount number of tasks and run the operations on them. There is a higher-level of abstraction too - Parallel, which you can look into.
You are using Console.WriteLine method which is an IO method, and does not scale well for multi-threaded operations (see here), and does not support asynchronous operations. So you are likely to not to have a control over this.
But the question is, do you really need such an application? I don't think so; no body wants to write that amount of text for output at once. Writing into file, maybe, which supports asynchronous operations.
As a simple improvement, you can use StringBuilder instead of creating many short-lived String objects as follows:
static void Main(string[] args)
{
string str = Console.ReadLine();
if (str == "start")
{
Stopwatch sw = new Stopwatch();
var builder = new StringBuilder();
for (int i = 1; i < 200000; i++)
{
sw.Start();
builder.Clear();
string a = builder.Append("Acccessed Value").Append(i.ToString()).ToString();
builder.Clear();
string b = builder.Append("Time ").Append(sw.ElapsedMilliseconds);
Console.WriteLine(a);
Console.WriteLine(b);
}
}
Console.Read();
}
class Program
{
static void Main(string[] args)
{
new Program();
}
private static int prepTotal;
private static readonly object Lock = new object();
public Program()
{
var sw = new Stopwatch();
sw.Start();
Parallel.For((long) 0, 10,new ParallelOptions {MaxDegreeOfParallelism = 1}, (j) =>
{
DoIt();
});
sw.Stop();
Console.WriteLine($"1 thread sum time is {prepTotal} ms. Total time is {sw.ElapsedMilliseconds} ms.");
sw.Restart();
prepTotal = 0;
Parallel.For((long)0, 10, new ParallelOptions { MaxDegreeOfParallelism = 3 }, (j) =>
{
DoIt();
});
sw.Stop();
Console.WriteLine($"3 thread sum time is {prepTotal} ms. Total time is {sw.ElapsedMilliseconds} ms.");
sw.Restart();
prepTotal = 0;
Parallel.For((long)0, 10, new ParallelOptions { MaxDegreeOfParallelism = 1 }, (j) =>
{
DoIt();
});
sw.Stop();
Console.WriteLine($"1 thread sum time is {prepTotal} ms. Total time is {sw.ElapsedMilliseconds} ms.");
sw.Restart();
prepTotal = 0;
Parallel.For((long)0, 10, new ParallelOptions { MaxDegreeOfParallelism = 3 }, (j) =>
{
DoIt();
});
sw.Stop();
Console.WriteLine($"3 thread sum time is {prepTotal} ms. Total time is {sw.ElapsedMilliseconds} ms.");
Console.ReadLine();
}
private static void DoIt()
{
var sw2 = new Stopwatch();
sw2.Start();
using (var bmp = new Bitmap(3000, 3000))
{
}
sw2.Stop();
lock (Lock)
{
prepTotal += (int) sw2.ElapsedMilliseconds;
}
}
}
When I run my test code(derived from original really complex code) I got following results. As you can see code running in more threads is almost 3 times slower. Is Bitmap constructor makes some blocking or what?
1 thread sum time is 125 ms. Total time is 132 ms.
3 thread sum time is 360 ms. Total time is 132 ms.
1 thread sum time is 121 ms. Total time is 127 ms.
3 thread sum time is 364 ms. Total time is 128 ms.
Well, I just used a profiler see if my guess is correct, and indeed, new Bitmap(3000, 3000) is almost entirely memory bound. So unless you have a server machine with multiple independent memory systems, adding more CPU doesn't help any. The bottleneck is memory.
The second most important part happens in the Dispose, which is again... almost entirely memory bound.
Multi-threading only helps with CPU-bound code. Since the CPU is much faster than any memory you may have in your system, the CPU is only really saturated when it can avoid working with memory (and other I/O devices). Your case is pretty much exactly the opposite - there's very little CPU work, and where there is CPU work, it's mostly synchronized (e.g. requesting and freeing virtual memory). Not a lot of opportunities for parallelization.
I wrote a simple console app to test the performance of Parallel.Invoke based on Microsoft's example on msdn:
public static void TestParallelInvokeSimple()
{
ParallelOptions parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = 1 }; // 1 to disable threads, -1 to enable them
Parallel.Invoke(parallelOptions,
() =>
{
Stopwatch sw = new Stopwatch();
sw.Start();
Console.WriteLine("Begin first task...");
List<string> objects = new List<string>();
for (int i = 0; i < 10000000; i++)
{
if (objects.Count > 0)
{
string tempstr = string.Join("", objects.Last().Take(6).ToList());
objects.Add(tempstr + i);
}
else
{
objects.Add("START!");
}
}
sw.Stop();
Console.WriteLine("End first task... {0} seconds", sw.Elapsed.TotalSeconds);
},
() =>
{
Stopwatch sw = new Stopwatch();
sw.Start();
Console.WriteLine("Begin second task...");
List<string> objects = new List<string>();
for (int i = 0; i < 10000000; i++)
{
objects.Add("abc" + i);
}
sw.Stop();
Console.WriteLine("End second task... {0} seconds", sw.Elapsed.TotalSeconds);
},
() =>
{
Stopwatch sw = new Stopwatch();
sw.Start();
Console.WriteLine("Begin third task...");
List<string> objects = new List<string>();
for (int i = 0; i < 20000000; i++)
{
objects.Add("abc" + i);
}
sw.Stop();
Console.WriteLine("End third task... {0} seconds", sw.Elapsed.TotalSeconds);
}
);
}
The ParallelOptions is to easily enable/disable threading.
When I disable threading I get the following output:
Begin first task...
End first task... 10.034647 seconds
Begin second task...
End second task... 3.5326487 seconds
Begin third task...
End third task... 6.8715266 seconds
done!
Total elapsed time: 20.4456563 seconds
Press any key to continue . . .
When I enable threading by setting MaxDegreeOfParallelism to -1 I get:
Begin third task...
Begin first task...
Begin second task...
End second task... 5.9112167 seconds
End third task... 13.113622 seconds
End first task... 19.5815043 seconds
done!
Total elapsed time: 19.5884057 seconds
Which is practically the same speed as sequential processing. Since task 1 takes the longest - about 10 seconds, I would expect the threading to take around 10 seconds total to run all 3 tasks. So what gives? Why is Parallel.Invoke running my tasks slower individually, yet in parallel?
BTW, I've seen the exact same results when using Parallel.Invoke in a real app performing many different tasks at the same time (most of which are running queries).
If you think it's my pc, think again... it's 1 year old, with 8GB of RAM, windows 8.1, Intel Core I7 2.7GHz 8 core cpu. My PC is not overloaded as I watched the performance while running my tests over and over again. My PC never maxed out but obviously showed cpu and memory increase when running.
I haven't profiled this, but the majority of the time here is probably being spent doing memory allocation for those lists and tiny strings. These "tasks" aren't actually doing anything other than growing the lists with minimal input and almost no processing time.
Consider that:
objects.Add("abc" + i);
is essentially just creating a new string and then adding it to a list. Creating a small string like this is largely just a memory allocation exercise since strings are stored on the heap. Furthermore, the memory allocated for the List is going to fill up rapidly - each time it does the list will re-allocate more memory for its own storage.
Now, heap allocations are serialized within a process - four threads inside one process cannot allocate memory at the same time. Requests for memory allocation are processed in sequence since the shared heap is like any other shared resource that needs to be protected from concurrent mayhem.
So what you have are three extremely memory-hungry threads that are probably spending most of their time waiting for each other to finish getting new memory.
Fill those methods with CPU intensive work (ie : do some math, etc) and you'll see the results are very different. The lesson is that not all tasks are efficiently parallelizable and not all in the ways that you might think. The above, for example, could be sped up by running each task within its own process - with its own private memory space there would be no contention for memory allocation, for example.
I have a method that looks like this:
public void SomeMethodThatLoadsUserData()
{
Method1();
Method2();
Method3();
.....
Method12();
}
These get executed when the user logs on and each method fetches some data related to the user. I was wondering if making these run in parallel would have any performance benefit because each method ends up calling a query to the same database file. And, if there would be a performance benefit, how would I rewrite this code?
Thanks for your suggestions.
The following code demonstrates a parallel test using a list of Thread and Stopwatch objects. I think this is pretty good method to test with because it guarantees a parallel execution attempt (unlike Parallel.Invoke) and it's easier to set up than using the ThreadPool IMO.
public static void SomeMethodThatLoadsUserData()
{
Stopwatch s = new Stopwatch();
s.Start();
List<Thread> threads = new List<Thread> {new Thread(Method1), new Thread(Method2)};
foreach (Thread thread in threads)
{
thread.Start();
}
foreach (Thread thread in threads)
{
thread.Join();
}
s.Stop();
Console.WriteLine("Total: {0} ms", s.ElapsedMilliseconds);
Console.ReadKey();
}
private static void Method1()
{
Stopwatch s = new Stopwatch();
s.Start();
// do work
Thread.Sleep(1000);
s.Stop();
Console.WriteLine("Method 1: {0} ms", s.ElapsedMilliseconds);
}
private static void Method2()
{
Stopwatch s = new Stopwatch();
s.Start();
// do work
Thread.Sleep(1000);
s.Stop();
Console.WriteLine("Method 2: {0} ms", s.ElapsedMilliseconds);
}
Output:
Method 1: 999 ms
Method 2: 999 ms
Total: 1051 ms
Any time saving will show up when (hopefully) Total is less than the sum of each method.
I don't know if this is the fastest or the best way of doing it but you could spin each method off to a new thread.
Thread t = new Thread(() => Method1());
t.Start();