Why my task work only once? - c#

I want to print every 2 sec number but and in the end i get only 0 what i need to do to get this every 2 sec?
result:
0
1
.
.
49
private static void Main(string[] args) {
Send();
}
public static async Task Send() {
for (int i = 0; i < 50; i++) {
Console.WriteLine(i);
await Task.Delay(2000);
}
}

well, simply because your Main method won't wait for the send method to finish and you can't use the await keyword in order for that to happened since the compiler won't allow an async Main, in that case you could simple use a Task.Run
private static void Main(string[] args)
{
Task.Run(async () =>
{
await Send();
}).Wait();
}
public static async Task Send()
{
for (int i = 0; i < 50; i++)
{
Console.WriteLine(i);
await Task.Delay(2000);
}
}

What you are missing is a Console.ReadLine() call, to halt the console from exiting the program before your task gets executed. Tested the code below and it works.
private static void Main(string[] args)
{
Send();
Console.ReadLine();
}
public static async Task Send()
{
for (int i = 0; i < 50; i++)
{
Console.WriteLine(i);
await Task.Delay(2000);
}
}

Building on Josephs answer, but in a more general "How to do asynchronous console apps"-way
Using asynchronous code in console apps can be a bit tricky. I generally use a substitute MainAsync method that the original Main() calls and makes a blocking wait on.
Here comes an example of how it could be done:
class Program
{
static void Main(string[] args)
{
Task mainTask = MainAsync(args);
mainTask.Wait();
// Instead of writing more code here, use the MainAsync-method as your new Main()
}
static async Task MainAsync(string[] args)
{
await Send();
Console.ReadLine();
}
public static async Task Send()
{
for (int i = 0; i < 50; i++)
{
Console.WriteLine(i);
await Task.Delay(2000);
}
}
}

Related

How to call multiple methods parallelly by using async programming in C#

public class Program
{
public static void Main(string[] args)
{
Start();
Console.ReadLine();
}
private static async Task Start()
{
var m1 = method1();
var m2 = method2();
await Task.WhenAll(m1, m2);
}
private static async Task method1()
{
Console.WriteLine("Method1 - Start");
Thread.Sleep(1000);
Console.WriteLine("Method1 - End");
}
private static async Task method2()
{
Console.WriteLine("Method2 - Start");
Thread.Sleep(1000);
Console.WriteLine("Method2 - End");
}
}
The above code returning below out
Method1 - Start
Method1 - End
Method2 - Start
Method2 - End
I want an output like
Method1 - Start
Method2 - Start
Method1 - End
Method2 - End
how to achieve that basically how to run async methods in parallel
Option A - with Task.Delay
public class Program
{
public static async Task Main()
{
await Start();
Console.ReadLine();
}
private static async Task Start()
{
var m1 = method1();
var m2 = method2();
await Task.WhenAll(m1, m2);
}
private static async Task method1()
{
Console.WriteLine("Method1 - Start");
await Task.Delay(1000);
Console.WriteLine("Method1 - End");
}
private static async Task method2()
{
Console.WriteLine("Method2 - Start");
await Task.Delay(1000);
Console.WriteLine("Method2 - End");
}
}
Option B - with Task.Run
public class Program
{
public static async Task Main()
{
await Start();
Console.ReadLine();
}
private static async Task Start()
{
var m1 = Task.Run(() => method1());
var m2 = Task.Run(() => method2());
await Task.WhenAll(m1, m2);
}
private static void method1()
{
Console.WriteLine("Method1 - Start");
Thread.Sleep(1000);
Console.WriteLine("Method1 - End");
}
private static void method2()
{
Console.WriteLine("Method2 - Start");
Thread.Sleep(1000);
Console.WriteLine("Method2 - End");
}
}
Or you can use Task.Yield().
public class Program
{
public static void Main(string[] args)
{
Start();
Console.ReadLine();
}
private static async Task Start()
{
var m1 = method1();
var m2 = method2();
await Task.WhenAll(m1, m2);
}
private static async Task method1()
{
await Task.Yield();
Console.WriteLine("Method1 - Start");
Thread.Sleep(1000);
Console.WriteLine("Method1 - End");
}
private static async Task method2()
{
await Task.Yield();
Console.WriteLine("Method2 - Start");
Thread.Sleep(1000);
Console.WriteLine("Method2 - End");
}
}
This one is a bit "more parallel" than using Task.Delay() because it immediately yields back an uncomplete task, but with delay the "asynchronicity" only happens when you reach that line of code. If you have long running sync code before the delay, that will delay the execution of subsequent methods (in this case method2).
Edit
a more detailed explanation on When would I use Task.Yield()?

Cancel task that invoke 3rd party long running method

I read some articles how to corectly cancel a task. Most of them describe: "you have to just add ThrowIfCancellationRequested() inside the method that is long running" - and that's it.
Ok - everything is clear but how to do it properly if we cannot modify method?
Please take a look on "DLL" class. I thought about to get current thread and abort it but that operation
is doesn't recommended by most of programmers. So my question is: how to do it properly?
Little example:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace LongRunningTask
{
static class ClassWithAccess
{
public static void DoHeavyOperation(CancellationToken ct)
{
for (int i = 0; i < 10000000; i++)
{
Thread.Sleep(500);
ct.ThrowIfCancellationRequested();
Console.WriteLine("inside local method that we can modify");
}
}
}
static class DLL
{
public static void DoHeavyOperation()
{
for (int i = 0; i < 10000000; i++)
{
Thread.Sleep(500);
//ct.ThrowIfCancellationRequested(); we can't do this
Console.WriteLine("inside DLL");
}
}
}
class Program
{
static void Main(string[] args)
{
CancellationTokenSource src = new CancellationTokenSource();
CancellationToken ct = src.Token;
Console.WriteLine("start");
Task.Run(() =>
{
//ClassWithAccess.DoHeavyOperation(ct);
DLL.DoHeavyOperation();
}, ct);
Thread.Sleep(3000);
src.Cancel();
Console.WriteLine("Cancel");
Console.ReadKey();
}
}
}

Run tasks in parallel and some of them consecutively

I want to run method A and method B1 in parallel. This is working. But how can I run a method B2 after B1 has finished?
class Program
{
static void Main(string[] args)
{
//var firstTask = Task.Factory.StartNew(() => MethodB1());
//var secondTask = firstTask.ContinueWith( (antecedent) => MethodB2());
Action[] actionsArray =
{
() => MethodA(),
() => MethodB1(),
};
Parallel.Invoke(actionsArray);
}
private static void MethodA()
{
Console.WriteLine("A");
// more code is running here (30 min)
}
private static void MethodB1()
{
Console.WriteLine("B1");
// more code is running here (2 min)
}
private static void MethodB2()
{
Console.WriteLine("B2");
}
}
Edit:
I hope the following example will stop the confusion. ;)
A -> A -> A -> A -> A -> A -> A -> A -> A -> A -> A -> A -> A -> A
B1 -> B1 -> B1 -> B1 -> B1 -> B2 -> B2 -> B2
C# is a great language to do this and there are many ways to do it one is as the comment suggests another is this:
static void Main()
{
var t = MethodA();
MethodB1().ContinueWith((r) =>
MethodB2()).Wait();
t.Wait();
}
private static async Task MethodA()
{
await Task.Run(() =>
{
for (int i = 0; i < 40; i++)
{
Thread.Sleep(100);
Console.WriteLine("A");
}
});
}
private static async Task MethodB1()
{
await Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(100);
Console.WriteLine("B1");
}
});
}
private static void MethodB2()
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(100);
Console.WriteLine("B2");
}
}
You can easily achieve this by using ContinueWith. Here is the code
public static void Main(string[] args)
{
var t1 = Task.Factory.StartNew(MethodA);
var t2 = Task.Factory.StartNew(MethodB1).ContinueWith(task => MethodB2());
Task.WaitAll(t1, t2); // If you want to wait here for finishing the above tasks
}
To depict the output you can try with the following implementation of MethodA, MethodB1 and MethodB2
private static void MethodA()
{
for (int i = 0; i < 100; i++)
{
Console.Write("A ");
Thread.Sleep(100);
}
}
private static void MethodB1()
{
for (int i = 0; i < 100; i++)
{
Console.Write("B1 ");
Thread.Sleep(100);
}
}
private static void MethodB2()
{
for (int i = 0; i < 100; i++)
{
Console.Write("B2 ");
Thread.Sleep(100);
}
}
This will not work with VS2017 and newer because async keyword is not supported on console app mains before VS2017. On older version, instead of await Task.WhenAll() you should do Task.WhenAll().Wait();
namespace ConsoleApp3
{
class Program
{
static async void Main(string[] args)
{
var taskA = Task.Run(() => MethodA()); //Start runnning taskA
var taskB1AndB2 = Task.Run(() => MethodB1()).ContinueWith(async (taskb1) => { await taskb1; await Task.Run(()=>MethodB2()); }).Unwrap(); //When taskB1 is complete, continue with taskB2
await Task.WhenAll(taskA, taskB1AndB2); //wait until all 3 tasks are completed
}
private static void MethodA()
{
Console.WriteLine("A");
// more code is running here (30 min)
}
private static void MethodB1()
{
Console.WriteLine("B1");
// more code is running here (2 min)
}
private static void MethodB2()
{
Console.WriteLine("B2");
}
}
}
One way is Delegate CallBack Mechanism class Program. The another can be event based Here is Used First approach . Given with time samples
This is exactly what you want
class Program
{
static System.Collections.Concurrent.ConcurrentQueue<Action> leftOvers = new System.Collections.Concurrent.ConcurrentQueue<Action>();
static void Main(string[] args)
{
for (int i = 0; i < 100; i++)
{
Task.WaitAll(MethodA(), MethodB1(MethodB2));
}
Action callBack = null;
while (leftOvers.TryDequeue(out callBack))
{
callBack();
}
Console.ReadLine();
}
private static void QueueMethods(Action method)
{
leftOvers.Enqueue(method);
}
private async static Task MethodA()
{
await Task.Run(() => Console.WriteLine("A at" + DateTime.Now.TimeOfDay ));
}
private async static Task MethodB1(Action callBack)
{
await Task.Run(() => Console.WriteLine("B1 at" + DateTime.Now.TimeOfDay));
leftOvers.Enqueue(callBack);
}
private static void MethodB2()
{
Console.WriteLine("B2 at" + DateTime.Now.TimeOfDay);
}
}
Just add B2 after Parallel.Invoke. Parallel.Invoke waits to finish before going to the next line. https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-use-parallel-invoke-to-execute-parallel-operations
public static void Main(string[] args)
{
Action[] actionsArray =
{
() => MethodA(),
() => MethodB1()
};
Parallel.Invoke(actionsArray);
MethodB2();
}
private static void MethodA()
{
Console.WriteLine("A");
Thread.Sleep(3000);
// more code is running here (30 min)
}
private static void MethodB1()
{
Console.WriteLine("B1");
Thread.Sleep(200);
// more code is running here (2 min)
}
private static void MethodB2()
{
Console.WriteLine("B2");
}

Why nothing is printed on the console?

I create 2 methods that print x and y 100 times. I want them to run concurrent and I expect the output to be xxxxyxyxyyyxyyxyx... sthg like that.
It doesn't print anything. Am I missing some logic here?
using System;
using System.Threading.Tasks;
namespace ConsoleApplication32
{
internal class Program
{
public static async Task<int> Print1()
{
await Task.Run(() =>
{
for (int i = 0; i < 100; i++)
{
Console.Write("x");
}
});
return 1;
}
public static async Task<int> Print2()
{
await Task.Run(() =>
{
for (int i = 0; i < 100; i++)
{
Console.Write("y");
}
});
return 1;
}
public static void Run()
{
Task<int> i = Print1();
Task<int> k = Print2();
}
private static void Main(string[] args)
{
Run();
}
}
}
Explanation
There are a couple things we need to tweak to get the desired output: xxxxyxyxyyyxyyxyx.
The Run method is not waiting for Task i and Task k to finish
This means that the console application will close before the two Tasks complete
As Andrei Matracaru mentions in his answer, if you add Console.ReadLine(), it will prevent the console application from closing before the strings have been printed to the screen.
A more elegant solution is to use Task.WhenAll. Task.WhenAll will allow the code yield to its calling thread (in this case, the Main Thread) which doesn't freeze the UI of the application, and allows the application to continue to print to the screen until the Tasks have completed. This may seem trivial for a simple console app, but it is crucial to never lock up the Main Thread when building any user-interactive application like mobile or web applications; locking up the Main Thread is what causing apps to "freeze".
Camilo Terevinto's answer above recommends Task.WaitAll. This is also bad practice because it will also freeze the application; Task.WaitAll is not awaitable and cannot not yield to the calling thread.
Print1() and Print2() never yield to the Main Thread
These methods are executing on a background thread, but they don't include an await inside of the for loop
An await is necessary inside of the for loop to allow CPU to continue executing the Main Thread, because Console.Write() can only print to the screen on the Main Thread.
Code
using System;
using System.Threading.Tasks;
namespace ConsoleApplication32
{
internal class Program
{
public static async Task<int> Print1()
{
for (int i = 0; i < 100; i++)
{
Console.Write("x");
await Task.Delay(10);
}
return 1;
}
public static async Task<int> Print2()
{
for (int i = 0; i < 100; i++)
{
Console.Write("y");
await Task.Delay(10);
}
return 1;
}
public static async Task Run()
{
var i = Print1();
var k = Print2();
await Task.WhenAll(i, k);
}
private static void Main(string[] args)
{
Task.Run(async () => await Run()).GetAwaiter().GetResult();
}
}
}
Output
xyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxxyxyxyxy
Press any key to continue...
C# 7.1 Alternative
C# 7.1 introduces the ability to have an async Main method. This means that we can tweak the Main method as follows:
...
private static async Task Main(string[] args)
{
await Run();
}
...
Tried your code and works just fine. Probably you think it doesn't work because the console window closes very fast. Add a Console.ReadLine() in your Main:
private static void Main(string[] args)
{
Run();
Console.ReadLine();
}
The problem is that you are not waiting for the tasks to complete, hence the program is terminating (no more synchronous code blocking).
If you want the tasks to run concurrently, do this instead:
public static void Run()
{
Task<int> i = Print1();
Task<int> k = Print2();
Task.WaitAll(i, k);
}
The other way to wait for this tasks to complete, would be to do this:
public static async Task Run()
{
Task<int> i = Print1();
Task<int> k = Print2();
await Task.WhenAll(i, k);
}
public static void Main(string[] args)
{
Run().GetAwaiter().GetResult();
}

ThreadAbortException with await

I'm facing a weird bug.
I have something like 100 long running tasks and I want to run 10 of them in the same time.
I found something very similar to my need here : http://msdn.microsoft.com/en-us/library/hh873173%28v=vs.110%29.aspx in the Throttling section.
Here the C# code after simplification :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
public class Program
{
static void Main(string[] args)
{
Test();
}
public static async void Test()
{
var range = Enumerable.Range(1, 100).ToList();
const int CONCURRENCY_LEVEL = 10;
int nextIndex = 0;
var matrixTasks = new List<Task>();
while (nextIndex < CONCURRENCY_LEVEL && nextIndex < range.Count())
{
int index = nextIndex;
matrixTasks.Add(Task.Factory.StartNew(() => ComputePieceOfMatrix()));
nextIndex++;
}
while (matrixTasks.Count > 0)
{
try
{
var imageTask = await Task.WhenAny(matrixTasks);
matrixTasks.Remove(imageTask);
}
catch (Exception e)
{
Console.Write(1);
throw;
}
if (nextIndex < range.Count())
{
int index = nextIndex;
matrixTasks.Add(Task.Factory.StartNew(() => ComputePieceOfMatrix()));
nextIndex++;
}
}
await Task.WhenAll(matrixTasks);
}
private static void ComputePieceOfMatrix()
{
try
{
for (int j = 0; j < 10000000000; j++) ;
}
catch (Exception e)
{
Console.Write(2);
throw;
}
}
}
}
When running it from a Unit Test a have a ThreadAbortException in ComputePieceOfMatrix.
Do you have any idea ?
Edit :
According to a comment, I tried this :
static void Main(string[] args)
{
Run();
}
private static async void Run()
{
await Test();
}
public static async Task Test()
{
var range = Enumerable.Range(1, 100).ToList();
But it's exactly the same.
1.Your code causes exception
try
{
for (int j = 0; j < 10000000000; j++) ;
}
catch (Exception e)
{
Console.Write(2);
throw;
}
Just a simple OverflowException becase 10000000000 - is long and j counter int.
2.Your main tread is exiting before child threads run to finish. Most likely you are getting ThreadAbortException because Threads are closed by runtime
3.await Test() - correctly just call Test(), and await Task.WhenAny without await as well
Change the return type of Test() to Task, then wait for that Task to finish before your program reaches the end.
static void Main(string[] args)
{
Test().Wait();
}
public static async Task Test()
{
// ...
}
I would change your Test from a void to a Task return type and in the main method I would do in place of Test();
Task t = Test();
t.Wait();

Categories