I am newbie to parallel programming. I write the basic code below but it doesnt run always as I excepted.
Console.WriteLine ("Start");
Task task = Task.Factory.StartNew(() => {
for (int i = 0; i < 5; i++)
{
Console.WriteLine (i);
}
});
Console.WriteLine ("End");
I usually could not get the result of the loop 8-9 out of 10 trials. Sometimes it prints the loop results, sometimes not. But I it always prints the Start and End. Whats happening at the behind side ? Why sometimes I could not get the result of loop from time to time ?
Thanks in advance,
Your program is terminating before the parallel loop gets a chance to print any output.
Console.WriteLine ("Start");
Task task = Task.Factory.StartNew(() => {
for (int i = 0; i < 5; i++)
{
Console.WriteLine (i);
}
});
Console.ReadLine();
Console.WriteLine("End");
Pause by waiting for input, and you'll see the loop run correctly.
Add a readline at the end. You will see the following:
Start
End
0
1
2
3
4
Console.WriteLine("Start");
Task task = Task.Factory.StartNew(() =>
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
}
});
Console.WriteLine("End");
Console.ReadLine();
You must tell your main thread to wait till your task is over.
Your "End" was being printed in most cases before the task thread executed. Use TaskContinuationOptions to tell the parent thread to wait for its tasks threads to complete.
Console.WriteLine ("Start");
Task task = Task.Factory.StartNew(() => {
for (int i = 0; i < 5; i++)
{
Console.WriteLine (i);
}
});
task.ContinueWith(ant =>
{
Console.WriteLine("End");
}, TaskContinuationOptions.NotOnFaulted| TaskContinuationOptions.AttachedToParent);
task.Wait();
Related
I have a loop that creates 5 Tasks. How can I insert a Delay of 5 seconds between each Task. I don't know how to fit Task.Delay(5000) in there.
var tasks = new List<Task<int>>();
for (var i = 0; i < 5; i++)
{
tasks.Add(ProcessQueueAsync());
}
await Task.WhenAll(tasks);
My ProcessQueAsync method calls a server, retrieves data and returns and int.
private async Task<int> ProcessQueAsync()
{
var result = await CallToServer();
return result.Count;
}
for (var i = 0; i < 5; i++)
{
tasks.Add(ProcessQueueAsync());
await Task.Delay(5000);
}
Or:
for (var i = 0; i < 5; i++)
{
await ProcessQueueAsync();
await Task.Delay(5000);
}
Depending on that you want.
If you want the tasks to run one after the other, with a 5 second delay, you should perhaps look at Task.ContinueWith instead of using Task.WhenAll. This would allow you to run tasks in serial rather than in parallel.
I have a Parallel.For loop which I use to peform a lot of HTTP request at a certain point when a scheduled task occurs like this:
Parallel.For(0, doc.GetElementsByTagName("ItemID").Count, i => {
var xmlResponse = PerformHttpRequestMethod();
});
Is there any way for me to set the loop to pause after the counter value hits 2,4,6,8,10 and so on...
so every 2 method calls it performs, sleep for 2 minutes lets say..
Is there any way I could achieve this ?
I recommend you to use Task.Delay.
Now your method is asyncronous using async/await.
public async Task DoSomething()
{
int i = 0;
while (i < doc.GetElementsByTagName("ItemID").Count)
{
Task.Run(() => PerformHttpRequestMethod());
if(i%2==0){
await Task.Delay(TimeSpan.FromMinutes(2));
//or simply:
await Task.Delay(120000);//120000 represents 2 minutes.
}
i++;
}
}
OR simply if you want to use for loop.
public async Task DoSomething()
{
for (int i = 0; i < doc.GetElementsByTagName("ItemID").Count; i++)
{
Task.Run(() => PerformHttpRequestMethod());
if(i%2==0){
await Task.Delay(TimeSpan.FromMinutes(2));
}
}
}
How would this 2nd example look if I'd want to do iterations from 0 to 4 then sleep 5 to 9 and so on... ?
public async Task DoSomething()
{
for (int i = 0; i < doc.GetElementsByTagName("ItemID").Count; i=i+5)
{
if( i%10 == 0 ){
for( int j=i;j<=i+4;j++){
Task.Run(() => PerformHttpRequestMethod());
}
}
else{
for(int j=i;j<=i+4;j++){
await Task.Delay(TimeSpan.FromMinutes(2));
}
}
}
}
Let's test the correctitude of algorithm.
i=0 -> (0%10==0 ->true) ,then will execute Task.Run(() => PerformHttpRequestMethod()) for i=(0,4)
i=5 -> (5%10==0 ->false), then will execute await Task.Delay(TimeSpan.FromMinutes(2)); for i=(5,9).
And so on...
I don't really see the point of using a Parallel.For if you want to sleep for x number of minutes or seconds every other iteration...how about using a plain old for loop?:
for(int i = 0; i < doc.GetElementsByTagName("ItemID").Count; ++i)
{
var xmlResponse = PerformHttpRequestMethod();
if (i % 2 == 0)
{
System.Threading.Thread.Sleep(TimeSpan.FromMinutes(2));
}
}
Or maybe you want to keep track of the how many iterations that are currently in flight?:
int inFlight = 0;
Parallel.For(0, doc.GetElementsByTagName("ItemID").Count, i => {
System.Threading.Interlocked.Increment(ref inFlight);
if (inFlight % 2 == 0)
System.Threading.Thread.Sleep(TimeSpan.FromMinutes(2));
var xmlResponse = PerformHttpRequestMethod();
System.Threading.Interlocked.Decrement(ref inFlight);
});
You can do that by combining a Parallel.For and a normal for loop:
for(var i = 0;i<doc.GetElementsByTagName("ItemID").Count;i = i+2)
{
Parallel.For(0, 2, i => {
var xmlResponse = PerformHttpRequestMethod();
});
Thread.Sleep(2000);
}
This question already has answers here:
Waiting for all threads to complete, with a timeout
(10 answers)
Closed 6 years ago.
I want the for loop to complete before I print the result, in:
for (int i = 0; i < 5; i++)
{
(new System.Threading.Thread(() =>
{
if (TimeTakingMethod())
{
++nResult;
}
})).Start();
}
Console.WriteLine("Count = " + nResult);
but Console.WriteLine will not wait for those threads to finish because printing is done on the main thread.
If I change it to:
System.Threading.Thread t = new System.Threading.Thread(() =>
{
for (int i = 0; i < 5; i++)
{
(new System.Threading.Thread(() =>
{
if (TimeTakingMethod())
{
++nResult;
}
})).Start();
}
});
t.Start();
t.Join();
Console.WriteLine("Count = " + nResult);
it will still not solve the problem because the nested threads will not be waited for.
Any simple solution to this? Thanks for going through this.
You should store the created threads to control them, I used a List.
int nResult = 0;
List<Thread> threads = new List<Thread>();
for (int i = 0; i < 5; i++)
{
Thread thread = new System.Threading.Thread(() =>
{
if (TimeTakingMethod())
{
++nResult;
}
});
thread.Start();
threads.Add(thread);
}
foreach (Thread thread in threads)
thread.Join();
Console.WriteLine("Count = " + nResult);
An example of how you could do this:
int result = 0;
Task.WaitAll(Enumerable.Range(0, 5)
.Select(index => Task.Factory.StartNew(() =>
{
// Do thread things...
Interlocked.Increment(ref result);
})).ToArray());
Console.WriteLine(result);
The two important things to note are Task.WaitAll which will cause the program to wait for all tasks to complete before moving on to the WriteLine call.
Also Interlocked.Increment will allow you to safely increment result from any thread.
When I create a Task :
for (int i = 0; i < 5; i++)
{
// var testClient =
Task.Factory.StartNew(
() =>
{
TaskClient();
});
}
public static void TaskClient()
{
System.Console.WriteLine("--------------------");
}
But this does not start the Console Write Untill I wait for the task!!!
Task.Factory.StartNew(
() =>
{
TaskClient();
}).Wait();
Why do we need to call Wait , When I am already starting the thread using StartNew
#vcsjones has to be right. You don't see the result because program ended and window was closed.
I've tried your code and if I run the program from cmd, without debugger I can see the correct output. To make it a little more meaningful I've added another Console.WriteLine at the end of Main method:
for (int i = 0; i < 5; i++)
{
// var testClient =
Task.Factory.StartNew(
() =>
{
TaskClient();
});
}
Console.WriteLine("End of program execution.");
Returns:
End of program execution.
--------------------
--------------------
--------------------
--------------------
--------------------
As you can see, it works just fine.
If you want to wait with further execution untill all tasks are done, you can use Task.WaitAll static method:
var tasks = new Task[5];
for (int i = 0; i < 5; i++)
{
// var testClient =
tasks[i] = Task.Factory.StartNew(
() =>
{
TaskClient();
});
}
Task.WaitAll(tasks);
I thought that the following code would let all the 10 threads run, two at a time, and then print "done" after Release() is called 10 times. But that's not what happened:
int count = 0;
Semaphore s = new Semaphore(2, 2);
for (int x = 0; x < 10; x++)
{
Thread t = new Thread(new ThreadStart(delegate()
{
s.WaitOne();
Thread.Sleep(1000);
Interlocked.Increment(ref count);
s.Release();
}));
t.Start(x);
}
WaitHandle.WaitAll(new WaitHandle[] { s });
Console.WriteLine("done: {0}", count);
output:
done: 6
If the only way to implement the functionality I'm looking for is to pass an EventWaitHandle to each thread and then do a WaitAll() on an array of those EventWaitHandles, then what's the meaning of doing a WaitAll() on an array of only a semaphore? In other words, when does the waiting thread unblock?
WaitHandle.WaitAll just waits until all the handlers are in signalled state.
So when you call WaitHandle.WaitAll on one WaitHandle it works the same as you call s.WaitOne()
You can use, for example, the following code to wait for all the started threads, but allow two threads to run in parallel:
int count = 0;
Semaphore s = new Semaphore(2, 2);
AutoResetEvent[] waitHandles = new AutoResetEvent[10];
for (int x = 0; x < 10; x++)
waitHandles[x] = new AutoResetEvent(false);
for (int x = 0; x < 10; x++)
{
Thread t = new Thread(threadNumber =>
{
s.WaitOne();
Thread.Sleep(1000);
Interlocked.Increment(ref count);
waitHandles[(int)threadNumber].Set();
s.Release();
});
t.Start(x);
}
WaitHandle.WaitAll(waitHandles);
Console.WriteLine("done: {0}", count);
WaitHandle.WaitAll(new WaitHandle[] { s }); waits just like s.WaitOne();. It enters at the first opportunity. You seem to expect this call to wait for all other semaphore operations but there is no way the operating system can tell the difference. This command might well be the first that is granted access to the semaphore.
I think what you need is the Barrier class. It is made for fork-join-style parallelism.