To demonstrate asynchronous flow of C# I have written a simple program
( To show its difference from Python, as Python is synchronous because of GIL).
Why is execution of func2() waiting for func1() to finish?
void main()
{
Console.WriteLine("main");
func1();
func2();
}
public void func1()
{
Console.WriteLine("func1");
double i = 0;
while(true)
{
i += 1;
if (i > 100000000)
{
break;
}
}
func(3);
func(4);
}
public void func2()
{
Console.WriteLine("func2");
func(5);
func(6);
}
public void func(int number)
{
Console.WriteLine(number);
}
In func1(), I am running a loop to make program wait so that main() keep going and call func2() before func(3) and func(4). But every time, it runs in a synchronous fashion and print output in this order :
main
func1
3
4
func2
5
6
i.e. func2() is always called after func4() which I didn't expect in asynchronous flow.
Why is execution of func2() waiting for func1() to finish?
Thanks
C# does not make your program synchronous. All programs are synchronous (exception of multi-core). Even the OS runs synchronously and only gives the illusion of parallel processing by giving various programs time slices of execution. If you want your program to run parallel you have to explicitly tell it so. C#/.NET have many mechanisms to do this but it is not fair to say a language is asynchronous. Multi-thread code can be written in C to run on windows but if you are working on an embedded system that doesn't support parallel processing you cant.
If you want func2 not to wait for func1 to finish, you need to tell it so:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("main");
doWork();
}
public async static void doWork()
{
Task<int> longTask = func1(); //Start func1
func2(); //Call func2 while we wait
int output = await longTask; //Wait for func2 to be finished
}
public async static Task<int> func1()
{
Console.WriteLine("func1");
await Task.Delay(10000); //delay, could make func(3) and func(4) run in the meantime if we wanted....
func(3);
func(4);
return 0;
}
public static void func2()
{
Console.WriteLine("func2");
func(5);
func(6);
}
public static void func(int number)
{
Console.WriteLine(number);
}
}
Outputs:
main
func1
func2
5
6
3
4
This happens because every time a method is invoked, in C#, the information passed to the parameter is stored in a stack (call stack). This stack is implemented as first in last out.
So in your example when the func1 is invoked it goes to stack, the main method will stop and wait for the func1 to leave the stack.
https://en.wikipedia.org/wiki/Call_stack
There is no way to do what you want without asynchronous flow and I suspect it is the same for python, too.
However you can easily change your code to execute it asynchronous.
public static void Main()
{
Console.WriteLine("main");
var t = func1();
func2();
t.Wait();
}
public static Task func1()
{
Console.WriteLine("func1");
return Task.Factory.StartNew(() => {
double i = 0;
while(true)
{
i += 1;
if (i > 100000000)
{
break;
}
}
func(3);
func(4);
});
}
public static void func2()
{
Console.WriteLine("func2");
func(5);
func(6);
}
public static void func(int number)
{
Console.WriteLine(number);
}
Related
I would like to know if there 'right' method to loop one task forever?
What I've tried:
private static void A()
{
Task.Run(B);
}
private static async Task B()
{
while (true)
{
Task Delay = Task.Delay(10000);
await C();
await Delay;
}
}
private static async Task C()
{
// some async code that will work every 10s
}
It is working, but I want to understand is there any better options to do the same.
Thanks in advance.
I'm making a TCP server. I'm using async/await to handle the multi-threading. The methods I am using for listening to incoming clients and there subsequent messages look a bit like this:
private static async Task Listener()
{
while (Online)
{
TcpClient socket = await tcpListener.AcceptTcpClientAsync();
OnReceivedTcpClient(socket);
}
}
As you can tell, this method isn't expected to return anytime soon. The question I have is regarding how I should call this listener method. Currently the way I'm doing it is this:
(Console App)
In Program.cs within Main, I call Server.Start()
static void Main(string[] args)
{
Console.Title = "Server (Prototype)";
Server.Start(100, 26950);
ConsoleKeyInfo input;
do
{
input = Console.ReadKey();
// check input and do stuff
}
}
while (input.Key != ConsoleKey.C);
}
Server.Start initilises some values and then calls an event which in turn calls the listener
private static event EventHandler<EventArgs> StartEvent;
private static void OnStartEvent() => StartEvent?.Invoke(null, new EventArgs());
public static void Start(int maxClients, int port)
{
Stop();
Console.WriteLine("Starting server...");
Init(maxClients, port);
OnStartEvent();
}
private async void ServerOnStartEvent(object sender, EventArgs e)
{
Online = true;
Console.WriteLine($"Server started on port {Port}");
await Listener();
}
If I had called await Listener(); inside of Server.Start then that method would need the async keyword, and it would have to either return void (Which I know is not an ideal design) or return a Task which then means I would have to call _ = Server.Start() inside program.cs (Which also is not great design).
So my question is, is my solution a good way of awaiting an async Task method and are there better ways to go about it?
The way I usually deal with this is to also add a Stop-method. So Start launches the task and saves it in a field. the stop method requests the task to stop (by whatever means), and returns the task that was stored.
So the caller can await the result from the stop method, and once the task completes, the caller can be sure any resources are cleaned up etc.
A variant would be to let the Start method return something like a IAsyncDisposable, that could allow the using-statement to automatically stop and wait for cleanup when going out of scope.
Example:
public class MyClass
volatile bool stopRequested; // or use CancellationTokenSource
Task task;
public void Start() => task = Task.Run(DoWork); // Should probably make this "longRunning"
public void DoWork(){
while(!stopRequested){
// Do something that take a limited amount of time.
}
// Do cleanup
}
public Task Stop(){
stopRequested = true;
return task;
}
In case a method takes too long it would make sense to terminate it after a timeout.
Is it possible to implement Method like BreakMyMethod_afterTimeout?
public static void MyMethod()
{
//some code
}
public static async void BreakMyMethod_afterTimeout(int timeoutInSec)
{
//break MyMethod after timeout
}
public static void main()
{
BreakMyMethod_afterTimeout(60); //Is this possible to relize?
MyMethod();
//the program continues here after 60 seconds at the latest
}
currently I'm using a timer to poll every x seconds. I've seen that I could also use asyncronous tasks to execute a function after x seconds.
So I've created an example for reproduction. This is how I would use a polling timer
class UseTimer
{
public UseTimer()
{
Console.WriteLine("Foo");
Timer myTimer = new Timer(2000);
myTimer.Elapsed += (object sender, ElapsedEventArgs e) =>
{
Console.WriteLine("Bar");
myTimer.Enabled = false;
};
myTimer.Enabled = true;
Console.ReadLine();
}
}
The code first logs Foo, then waits 2 seconds for the first timer tick and then logs Bar. I tried to reproduce it by using async/await
class UseAsync
{
public UseAsync()
{
Console.WriteLine("Foo");
Do().Wait();
Console.ReadLine();
}
private async Task Do()
{
await Task.Delay(2000);
Console.WriteLine("Bar");
}
}
The behaviour seems to be the same when I test it with this code
class Program
{
static void Main(string[] args)
{
// UseAsync a = new UseAsync();
UseTimer t = new UseTimer();
}
}
I would like to know if I could or even should switch to async because it's easier to maintain and takes out complexity but remains the same way under the hood.
"Every x seconds" is different from "after x seconds".
If you need to run something (repeatedly) every x seconds, use a Timer.
If you need to run something (only once) after x seconds, use Task.Delay.
As noted in the comments, Task.Delay uses a System.Threading.Timer anyway, it's just easier to use for a single wait, and keeps your code clean.
Also, it's not wise to use asynchronous methods in a class constructor. Class constructors cannot be async, and thus you end up blocking the thread (as you did when using Wait()), or "fire and forget". If you need to do anything asynchronous while creating a new object, you can use a "factory method": a static method that creates the object for you. Then you make the constructor private to force everyone to use the factory method:
class UseAsync
{
private UseAsync() {}
public static async Task<UseAsync> CreateUseAsync()
{
var myC = new UseAsync();
await myC.Do();
return myC;
}
private async Task Do()
{
await Task.Delay(2000);
Console.WriteLine("Bar");
}
}
Then you can create an instance like this:
var a = await UseAsync.CreateUseAsync();
I've done this when I need to retrieve data from somewhere before an object is actually useful.
The console.readline should be outside useAsync method, if not the task Do will not be executed
class Program
{
static void Main(string[] args)
{
UseAsync.UseAsyn();
Console.ReadLine();
}
}
static class UseAsync
{
public static async Task UseAsyn()
{
Console.WriteLine("Foo");
await Do();
}
private static async Task Do()
{
await Task.Delay(2000);
Console.WriteLine("Bar");
}
}
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();
}