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();
Related
I can't figure out how to control the execution of parallel calls to Task.WaitAll() which I use to execute long and short running work.
To illustrate the problem I wrote this litte test program:
class TaskTest
{
private static void Work(object c)
{
int count = (int)c;
//Start c Tasks which need 1s each
List<Task> taskList = new List<Task>(count);
for (int i = 0; i < count; i++)
{
Task task = Task.Run(() =>
{
Thread.Sleep(count * 20);
});
taskList.Add(task);
}
Task.WaitAll(taskList.ToArray());
}
[STAThread]
static void Main(string[] args)
{
Thread thread = new Thread(Work);
thread.Start(50);
Console.WriteLine("Long work started...");
//ensure Worker-Thread has started to do something
Thread.Sleep(10);
Console.WriteLine("Start short work...");
Stopwatch watch = Stopwatch.StartNew();
Work(5);
watch.Stop();
Console.WriteLine("Time for short work: {0} s", watch.Elapsed.TotalSeconds);
Console.WriteLine("Wait for completion of long work...");
watch.Start();
thread.Join();
Console.WriteLine("Time for completion of long work: {0} s", watch.Elapsed.TotalSeconds);
}
}
A long running work is splitted into several little tasks (i.e. parallel calls to ADO.NET) which are then executed in a new thread. I use an explicit thread here to control its execution.
The main thread also does serveral things that can be splitted into litte tasks to optimize the performance. But this is "short work" in comparison with the long work (simulated by the sleep time count * 20).
To simulate the "litte tasks" I just use Thread.Sleep(1000).
The long work starts first and tries to execute 50 little tasks.
But then I want to use Task.WaitAll() for some other work parallel in the main thread (simulated with the call of Work(5);)
I expected to get some fresh threads for these 5 little tasks in a parallel manner. But that's not the case! I have to wait for completion of the 5 tasks nearly as long as for the 50 tasks.
The console output shows the following:
Long work started...
Start short work...
Time for short work: 9,4921011 s
Wait for completion of long work...
Time for completion of long work: 9,9916732 s
So my problem is: trying to optimize a methode with separate little tasks brings the opposite result for the short work because its tasks are scheduled for later execution. But I have to wait in the main thread for the completion of them...
Is there any way to prioritise the execution of tasks? Or should I follow a different approach to control the execution of such methods with high and low workload?
Any help would be appreciated.
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.
I have some code as follows:
public void Start()
{
var watch = new Stopwatch();
watch.Start();
Task.Factory.StartNew(MyMethod1);
Task.Factory.StartNew(MyMethod2);
watch.Stop();
Log(watch.ElapsedMilliseconds);
Task.Factory.StartNew(MyMethod3);
}
Because MyMethod1 and MyMethod2 are called Asynchronously watch.Stop() gets called at the wrong time. How I can ensure that .Stop gets called and logged after MyMethod1 and MyMethod2 finish BUT ensure that MyMethod3 does not have to wait.
I want to keep all Stopwatch functionality in my Start() method and not have the logging in any of my 3 methods i.e. MyMethod1, MyMethod2 and MyMethod3
You can use the Task.Factory.ContinueWhenAll method.
watch.Start();
var t1 = Task.Factory.StartNew(MyMethod1);
var t2 = Task.Factory.StartNew(MyMethod2);
Task.Factory.ContinueWhenAll(new [] {t1, t2}, tasks => watch.Stop());
If you're targeting for .NET 4.5 and upper, you can also use the method Task.WhenAll. It returns a task that will complete when all of the passed Task objects have completed.
Task.WhenAll(t1, t2).ContinueWith(t => watch.Stop());
You need create a new Thread that will handle the logging issue.
This logging thread will wait on EventWaitHandle.WaitAll(threadsEventWaitHandles) that will contain all the threads EventWaitHandles.
Something like that :
private void LoggingThread()
{
var watch = new Stopwatch();
watch.Start();
EventWaitHandle.WaitAll(threadsEventWaitHandles);
watch.Stop();
Log(watch.ElapsedMilliseconds);
}
And also the methods MyMethod1, MyMethod2 will signal to the loging thread whene they finish.
Something like that :
private void MyMethod1()
{
//... your code
EventWaitHandle.Set();
}
private void MyMethod2()
{
//... your code
EventWaitHandle.Set();
}
So you can ensure that MyMethod3 does not have to wait.
public void Start()
{
var watch = new Stopwatch();
watch.Start();
Task.Factory.StartNew(MyMethod1);
Task.Factory.StartNew(MyMethod2);
Task.WaitAll(); // Wait for previous tasks to finish
watch.Stop();
Log(watch.ElapsedMilliseconds);
Task.Factory.StartNew(MyMethod3);
}
I tried a very minimal example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Concurrent;
using System.Diagnostics;
namespace TPLExample {
class Program {
static void Main(string[] args) {
int[] dataItems = new int[100];
double[] resultItems = new double[100];
for (int i = 0; i < dataItems.Length; ++i) {
dataItems[i] = i;
}
Stopwatch stopwatch = new Stopwatch();
stopwatch.Reset();
stopwatch.Start();
Parallel.For(0, dataItems.Length, (index) => {
resultItems[index] = Math.Pow(dataItems[index], 2);
});
stopwatch.Stop();
Console.WriteLine("TPL Time elapsed: {0}", stopwatch.Elapsed);
stopwatch.Reset();
stopwatch.Start();
for (int i = 0; i < dataItems.Length; ++i) {
resultItems[i] = Math.Pow(dataItems[i], 2);
}
stopwatch.Stop();
Console.WriteLine("Sequential Time elapsed: {0}", stopwatch.Elapsed);
WaitForEnterKey();
}
public static void WaitForEnterKey() {
Console.WriteLine("Press enter to finish");
Console.ReadLine();
}
public static void PrintMessage() {
Console.WriteLine("Message printed");
}
}
}
The output was:
TPL Time elapsed: 00:00:00.0010670
Sequential Time elapsed: 00:00:00.0000178
Press enter to finish
The sequential loop is way faster than TPL! How is this possible? From my understanding, calculation within the Parallel.For will be executed in parallel, so must it be faster?
Simply put: For only iterating over a hundred items and performing a small mathematical operation, spawning new threads and waiting for them to complete produces more overhead than just running through the loop would.
From my understanding, calculation within the Parallel.For will be executed in parallel, so must it be faster?
As generally happens when people make sweeping statements about computer performance, there are far more variables at play here, and you can't really make that assumption. For example, inside your for loop, you are doing nothing more than Math.Pow, which the processor can perform very quickly. If this were an I/O intensive operation, requiring each thread to wait a long time, or even if it were a series of processor-intensive operations, you would get more out of Parallel processing (assuming you have a multi-threaded processor). But as it is, the overhead of creating and synchronizing these threads is far greater than any advantage that parallelism might give you.
Parallel loop processing is beneficial when the operation performed within the loop is relatively costly. All you're doing in your example is calculating an exponent, which is trivial. The overhead of multithreading is far outweighing the gains that you're getting in this case.
This code example is practical proof really nice answers above.
I've simulated intensive processor operation by simply blocking thread by Thead.Sleep.
The output was:
Sequential Loop - 00:00:09.9995500
Parallel Loop - 00:00:03.0347901
_
class Program
{
static void Main(string[] args)
{
const int a = 10;
Stopwatch sw = new Stopwatch();
sw.Start();
//for (long i = 0; i < a; i++)
//{
// Thread.Sleep(1000);
//}
Parallel.For(0, a, i =>
{
Thread.Sleep(1000);
});
sw.Stop();
Console.WriteLine(sw.Elapsed);
Console.ReadLine();
}
}
The overhead of parallelization is far greater than simply running Math.Pow 100 times sequentially. The others have said this.
More importantly, though, the memory access is trivial in the sequential version, but with the parallel version, the threads have to share memory (resultItems) and that kind of thing will really kill you even if you have a million items.
See page 44 of this excellent Microsoft whitepaper on parallel programming:
http://www.microsoft.com/en-us/download/details.aspx?id=19222. Here is an MSDN magazine article on the subject: http://msdn.microsoft.com/en-us/magazine/cc872851.aspx
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C# Spawn Multiple Threads for work then wait until all finished
I have two method calls that I want to call using two threads. Then I want them to wait till method executions get completed before continuing. My sample solution is something like below.
public static void Main()
{
Console.WriteLine("Main thread starting.");
String[] strThreads = new String[] { "one", "two" };
String ctemp = string.Empty;
foreach (String c in strThreads)
{
ctemp = c;
Thread thread = new Thread(delegate() { MethodCall(ctemp); });
thread.Start();
thread.Join();
}
Console.WriteLine("Main thread ending.");
Console.Read();
}
public static void MethodCalls(string number)
{
Console.WriteLine("Method call " + number);
}
Is this will do the job? Or is there another better way to do the same thing?
I'd look into running your method via ThreadPool.QueueUserWorkItem and then using WaitHandle.WaitAll to wait for all of them to complete.
This sequence of statements...:
Thread thread = new Thread(delegate() { MethodCall(ctemp); });
thread.Start();
thread.Join();
is equivalent to just calling the method directly -- since you're waiting for the new thread to finish right after starting it, there's no benefit from threading! You need to first start all threads in a loop (put them in an array list or some similar container), then join them in a separate loop, to get concurrent execution of the methods.
What you're doing ther eis creating a thread and then waiting to finish, one by one. You have, at any time, at most two thread running: the main and the one started.
What you want is to start all threads, then wait for all to complete:
public static void Main()
{
Console.WriteLine("Main thread starting.");
String[] strThreads = new String[] { "one", "two" };
int threadCount = strThreads.Length;
AutoResetEvent eventdone = new AutoResetEvent(false);
String ctemp = string.Empty;
foreach (String c in strThreads)
{
ctemp = c;
Thread thread = new Thread(delegate() {
try
{
MethodCall(ctemp);
}
finally
{
if (0 == Interlocked.Decrement(ref threadCount)
{
eventDone.Set();
}
}
});
thread.Start();
}
eventDone.WaitOne();
Console.WriteLine("Main thread ending.");
Console.Read();
}
public static void MethodCalls(string number)
{
Console.WriteLine("Method call " + number);
}
If you intended for your two threads to execute one after the other, then yes, the above code will suffice (though my C# syntax knowledge is a little fuzzy off the top of my head so I can't say if the above compiles nicely or not), but why use threads if you want ordered, synchronous execution?
If instead what you want is for the two method calls to execute in parallel, you need to take the thread.Join(); out of the for-loop (you'll need to hang on to the thread objects, likely in an array.)
Take a look at BackgroundWorker Component; I beleive it works with Windows Forms, WPF and Silverlight, basically somewhere UI is involved