Async in Program.cs [duplicate] - c#
I am new to asynchronous programming with the async modifier. I am trying to figure out how to make sure that my Main method of a console application actually runs asynchronously.
class Program
{
static void Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = bs.GetList();
}
}
public class Bootstrapper {
public async Task<List<TvChannel>> GetList()
{
GetPrograms pro = new GetPrograms();
return await pro.DownloadTvChannels();
}
}
I know this is not running asynchronously from "the top." Since it is not possible to specify the async modifier on the Main method, how can I run code within main asynchronously?
As you discovered, in VS11 the compiler will disallow an async Main method. This was allowed (but never recommended) in VS2010 with the Async CTP.
Update, 2017-11-30: As of Visual Studio 2017 Update 3 (15.3), the language now supports an async Main - as long as it returns Task or Task<T>. So you can now do this:
class Program
{
static async Task Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
The semantics appear to be the same as the GetAwaiter().GetResult() style of blocking the main thread. However, there's no language spec for C# 7.1 yet, so this is only an assumption.
I have recent blog posts about async/await and asynchronous console programs in particular. Here's some background info from the intro post:
If "await" sees that the awaitable has not completed, then it acts asynchronously. It tells the awaitable to run the remainder of the method when it completes, and then returns from the async method. Await will also capture the current context when it passes the remainder of the method to the awaitable.
Later on, when the awaitable completes, it will execute the remainder of the async method (within the captured context).
Here's why this is a problem in Console programs with an async Main:
Remember from our intro post that an async method will return to its caller before it is complete. This works perfectly in UI applications (the method just returns to the UI event loop) and ASP.NET applications (the method returns off the thread but keeps the request alive). It doesn't work out so well for Console programs: Main returns to the OS - so your program exits.
One solution is to provide your own context - a "main loop" for your console program that is async-compatible.
If you have a machine with the Async CTP, you can use GeneralThreadAffineContext from My Documents\Microsoft Visual Studio Async CTP\Samples(C# Testing) Unit Testing\AsyncTestUtilities. Alternatively, you can use AsyncContext from my Nito.AsyncEx NuGet package.
Here's an example using AsyncContext; GeneralThreadAffineContext has almost identical usage:
using Nito.AsyncEx;
class Program
{
static void Main(string[] args)
{
AsyncContext.Run(() => MainAsync(args));
}
static async void MainAsync(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
Alternatively, you can just block the main Console thread until your asynchronous work has completed:
class Program
{
static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
static async Task MainAsync(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
Note the use of GetAwaiter().GetResult(); this avoids the AggregateException wrapping that happens if you use Wait() or Result.
You can solve this with this simple construct:
class Program
{
static void Main(string[] args)
{
Task.Run(async () =>
{
// Do any async anything you need here without worry
}).GetAwaiter().GetResult();
}
}
That will put everything you do out on the ThreadPool where you'd want it (so other Tasks you start/await don't attempt to rejoin a Thread they shouldn't), and wait until everything's done before closing the Console app. No need for special loops or outside libs.
Edit: Incorporate Andrew's solution for uncaught Exceptions.
You can do this without needing external libraries also by doing the following:
class Program
{
static void Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var getListTask = bs.GetList(); // returns the Task<List<TvChannel>>
Task.WaitAll(getListTask); // block while the task completes
var list = getListTask.Result;
}
}
In C# 7.1 you will be able to do a proper async Main. The appropriate signatures for Main method has been extended to:
public static Task Main();
public static Task<int> Main();
public static Task Main(string[] args);
public static Task<int> Main(string[] args);
For e.g. you could be doing:
static async Task Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
At compile time, the async entry point method will be translated to call GetAwaitor().GetResult().
Details: https://blogs.msdn.microsoft.com/mazhou/2017/05/30/c-7-series-part-2-async-main
EDIT:
To enable C# 7.1 language features, you need to right-click on the project and click "Properties" then go to the "Build" tab. There, click the advanced button at the bottom:
From the language version drop-down menu, select "7.1" (or any higher value):
The default is "latest major version" which would evaluate (at the time of this writing) to C# 7.0, which does not support async main in console apps.
I'll add an important feature that all of the other answers have overlooked: cancellation.
One of the big things in TPL is cancellation support, and console apps have a method of cancellation built in (CTRL+C). It's very simple to bind them together. This is how I structure all of my async console apps:
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
System.Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
cts.Cancel();
};
MainAsync(args, cts.Token).GetAwaiter.GetResult();
}
static async Task MainAsync(string[] args, CancellationToken token)
{
...
}
C# 7.1 (using vs 2017 update 3) introduces async main
You can write:
static async Task Main(string[] args)
{
await ...
}
For more details C# 7 Series, Part 2: Async Main
Update:
You may get a compilation error:
Program does not contain a static 'Main' method suitable for an entry point
This error is due to that vs2017.3 is configured by default as c#7.0 not c#7.1.
You should explicitly modify the setting of your project to set c#7.1 features.
You can set c#7.1 by two methods:
Method 1: Using the project settings window:
Open the settings of your project
Select the Build tab
Click the Advanced button
Select the version you want
As shown in the following figure:
Method2: Modify PropertyGroup of .csproj manually
Add this property:
<LangVersion>7.1</LangVersion>
example:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<LangVersion>7.1</LangVersion>
</PropertyGroup>
If you're using C# 7.1 or later, go with the nawfal's answer and just change the return type of your Main method to Task or Task<int>. If you are not:
Have an async Task MainAsync like Johan said.
Call its .GetAwaiter().GetResult() to catch the underlying exception like do0g said.
Support cancellation like Cory said.
A second CTRL+C should terminate the process immediately. (Thanks binki!)
Handle OperationCancelledException - return an appropriate error code.
The final code looks like:
private static int Main(string[] args)
{
var cts = new CancellationTokenSource();
Console.CancelKeyPress += (s, e) =>
{
e.Cancel = !cts.IsCancellationRequested;
cts.Cancel();
};
try
{
return MainAsync(args, cts.Token).GetAwaiter().GetResult();
}
catch (OperationCanceledException)
{
return 1223; // Cancelled.
}
}
private static async Task<int> MainAsync(string[] args, CancellationToken cancellationToken)
{
// Your code...
return await Task.FromResult(0); // Success.
}
Haven't needed this much yet, but when I've used console application for Quick tests and required async I've just solved it like this:
class Program
{
static void Main(string[] args)
{
MainAsync(args).Wait();
}
static async Task MainAsync(string[] args)
{
// Code here
}
}
For asynchronously calling task from Main, use
Task.Run() for .NET 4.5
Task.Factory.StartNew() for .NET 4.0 (May require Microsoft.Bcl.Async library for async and await keywords)
Details:
http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx
In Main try changing the call to GetList to:
Task.Run(() => bs.GetList());
When the C# 5 CTP was introduced, you certainly could mark Main with async... although it was generally not a good idea to do so. I believe this was changed by the release of VS 2013 to become an error.
Unless you've started any other foreground threads, your program will exit when Main completes, even if it's started some background work.
What are you really trying to do? Note that your GetList() method really doesn't need to be async at the moment - it's adding an extra layer for no real reason. It's logically equivalent to (but more complicated than):
public Task<List<TvChannel>> GetList()
{
return new GetPrograms().DownloadTvChannels();
}
Newest version of C# - C# 7.1 allows to create async console app. To enable C# 7.1 in project, you have to upgrade your VS to at least 15.3, and change C# version to C# 7.1 or C# latest minor version. To do this, go to Project properties -> Build -> Advanced -> Language version.
After this, following code will work:
internal class Program
{
public static async Task Main(string[] args)
{
(...)
}
As of C# 7.1 the following signatures are valid for the Main method.
public static void Main() { }
public static int Main() { }
public static void Main(string[] args) { }
public static int Main(string[] args) { }
public static async Task Main() { }
public static async Task<int> Main() { }
public static async Task Main(string[] args) { }
public static async Task<int> Main(string[] args) { }
So, now you can do async/await
static async Task Main(string[] args)
{
Console.WriteLine("Hello Asyn Main method!");
await Task.Delay(200);
}
On MSDN, the documentation for Task.Run Method (Action) provides this example which shows how to run a method asynchronously from main:
using System;
using System.Threading;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
ShowThreadInfo("Application");
var t = Task.Run(() => ShowThreadInfo("Task") );
t.Wait();
}
static void ShowThreadInfo(String s)
{
Console.WriteLine("{0} Thread ID: {1}",
s, Thread.CurrentThread.ManagedThreadId);
}
}
// The example displays the following output:
// Application thread ID: 1
// Task thread ID: 3
Note this statement that follows the example:
The examples show that the asynchronous task executes on a different
thread than the main application thread.
So, if instead you want the task to run on the main application thread, see the answer by #StephenCleary.
And regarding the thread on which the task runs, also note Stephen's comment on his answer:
You can use a simple Wait or Result, and there's nothing wrong
with that. But be aware that there are two important differences: 1)
all async continuations run on the thread pool rather than the main
thread, and 2) any exceptions are wrapped in an AggregateException.
(See Exception Handling (Task Parallel Library) for how to incorporate exception handling to deal with an AggregateException.)
Finally, on MSDN from the documentation for Task.Delay Method (TimeSpan), this example shows how to run an asynchronous task that returns a value:
using System;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
var t = Task.Run(async delegate
{
await Task.Delay(TimeSpan.FromSeconds(1.5));
return 42;
});
t.Wait();
Console.WriteLine("Task t Status: {0}, Result: {1}",
t.Status, t.Result);
}
}
// The example displays the following output:
// Task t Status: RanToCompletion, Result: 42
Note that instead of passing a delegate to Task.Run, you can instead pass a lambda function like this:
var t = Task.Run(async () =>
{
await Task.Delay(TimeSpan.FromSeconds(1.5));
return 42;
});
In my case I had a list of jobs that I wanted to run in async from my main method, have been using this in production for quite sometime and works fine.
static void Main(string[] args)
{
Task.Run(async () => { await Task.WhenAll(jobslist.Select(nl => RunMulti(nl))); }).GetAwaiter().GetResult();
}
private static async Task RunMulti(List<string> joblist)
{
await ...
}
To avoid freezing when you call a function somewhere down the call stack that tries to re-join the current thread (which is stuck in a Wait), you need to do the following:
class Program
{
static void Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
List<TvChannel> list = Task.Run((Func<Task<List<TvChannel>>>)bs.GetList).Result;
}
}
(the cast is only required to resolve ambiguity)
class Program
{
public static EventHandler AsyncHandler;
static void Main(string[] args)
{
AsyncHandler+= async (sender, eventArgs) => { await AsyncMain(); };
AsyncHandler?.Invoke(null, null);
}
private async Task AsyncMain()
{
//Your Async Code
}
}
This is hypothetical but I am thinking:
static void Main(string[] args)
{
var context = new Thread(() => /*do stuff*/);
context.Start();
context.Join();
}
Not sure if this is what you're looking for, but I wanted to await a method on load. I ended up using the Main_Shown handler and making it async:
private async void Main_Shown(object sender, EventArgs e)
{
await myAsyncMethod();
}
The following code can be used to make a main async. I've tweak it to use long running tasks (learn more here: https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcreationoptions?view=net-7.0)
It's also implementing the cancellation token from the above response.
private static int Main(string[] args)
{
var cts = new CancellationTokenSource();
Console.CancelKeyPress += (s, e) =>
{
e.Cancel = !cts.IsCancellationRequested;
cts.Cancel();
Console.WriteLine("CancellationRequested");
};
try
{
var task = new Task<int>(
() => MainAsync(args, cts.Token).GetAwaiter().GetResult(),
cts.Token,
TaskCreationOptions.LongRunning //https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcreationoptions?view=net-7.0
);
task.Start();
var exitCode = task.GetAwaiter().GetResult();
/*Or this.*/
//var exitCode = MainAsync(args, cts.Token).GetAwaiter().GetResult();
return exitCode;// MainAsync(args, cts.Token).GetAwaiter().GetResult();
}
catch (OperationCanceledException ex)
{
Console.WriteLine(ex);
return 1223; // Cancelled.
}
catch(Exception ex)
{
Console.WriteLine(ex);
return -1;
}
}
private static async Task<int> MainAsync(string[] args, CancellationToken cancellationToken)
{
await Something()
return;
}
In the following example I wrote. You can play with maxDegreeOfParallelism & numberOfIteration to understand / see how the task are handle. Good statring point for learning TPL!
private static async Task<int> MainAsync(string[] args, CancellationToken cancellationToken)
{
var infos = new ConcurrentBag<Info>();
var mySuperUselessService = new BigWorkload();
int numberOfSecond = 1;
int numberOfIteration = 25; //Experiment with this
int maxDegreeOfParallelism = 4; //Experiment with this
var simulateWorkTime = TimeSpan.FromSeconds(numberOfSecond);
var informations = Enumerable.Range(1, numberOfIteration)
.Select(x => new Info() { Index = x });
var count = informations.Count();
var chunkNeeded = Math.Round(count / Convert.ToDecimal(maxDegreeOfParallelism), MidpointRounding.ToPositiveInfinity);
var splashInfo = #$"
Press CTRL + C to cancel.
Processing {count} items, maxDegreeOfParallelism set to {maxDegreeOfParallelism}.
But it will be bound by the core on the machine {Environment.ProcessorCount}.
This operation should take ~{chunkNeeded * (numberOfSecond + 0.01m)}s
And will be starting test in 2s
";
Console.WriteLine(splashInfo);
await Task.Delay(TimeSpan.FromSeconds(2));
var parralelOptions = new ParallelOptions() { MaxDegreeOfParallelism = maxDegreeOfParallelism, CancellationToken = cancellationToken};
var stopwatch = new Stopwatch();
stopwatch.Start();
var forLoopTask = Parallel.ForEachAsync(informations, parralelOptions, async (info, token) =>
{
await mySuperUselessService.Simulate(simulateWorkTime, info);
Console.WriteLine(info);
infos.Add(info);
});
await forLoopTask;
stopwatch.Stop();
foreach (var grouped in infos.GroupBy(x => x.ManagedThreadId))
{
Console.WriteLine($"ThreadId: {grouped.Key}");
foreach (var item in grouped)
{
Console.WriteLine($"\t Index: {item.Index} {item.TaskCurrentId}");
}
}
Console.WriteLine($"NumberOfThread: {infos.GroupBy(x => x.ManagedThreadId).Count()}");
Console.WriteLine($"Elasped: {stopwatch.ElapsedMilliseconds / 1000d}s");
Console.WriteLine(splashInfo);
return 0;
}
Related
Unable to run Async Method without Console.ReadLine() Or Console.ReadKey() [duplicate]
I am new to asynchronous programming with the async modifier. I am trying to figure out how to make sure that my Main method of a console application actually runs asynchronously. class Program { static void Main(string[] args) { Bootstrapper bs = new Bootstrapper(); var list = bs.GetList(); } } public class Bootstrapper { public async Task<List<TvChannel>> GetList() { GetPrograms pro = new GetPrograms(); return await pro.DownloadTvChannels(); } } I know this is not running asynchronously from "the top." Since it is not possible to specify the async modifier on the Main method, how can I run code within main asynchronously?
As you discovered, in VS11 the compiler will disallow an async Main method. This was allowed (but never recommended) in VS2010 with the Async CTP. Update, 2017-11-30: As of Visual Studio 2017 Update 3 (15.3), the language now supports an async Main - as long as it returns Task or Task<T>. So you can now do this: class Program { static async Task Main(string[] args) { Bootstrapper bs = new Bootstrapper(); var list = await bs.GetList(); } } The semantics appear to be the same as the GetAwaiter().GetResult() style of blocking the main thread. However, there's no language spec for C# 7.1 yet, so this is only an assumption. I have recent blog posts about async/await and asynchronous console programs in particular. Here's some background info from the intro post: If "await" sees that the awaitable has not completed, then it acts asynchronously. It tells the awaitable to run the remainder of the method when it completes, and then returns from the async method. Await will also capture the current context when it passes the remainder of the method to the awaitable. Later on, when the awaitable completes, it will execute the remainder of the async method (within the captured context). Here's why this is a problem in Console programs with an async Main: Remember from our intro post that an async method will return to its caller before it is complete. This works perfectly in UI applications (the method just returns to the UI event loop) and ASP.NET applications (the method returns off the thread but keeps the request alive). It doesn't work out so well for Console programs: Main returns to the OS - so your program exits. One solution is to provide your own context - a "main loop" for your console program that is async-compatible. If you have a machine with the Async CTP, you can use GeneralThreadAffineContext from My Documents\Microsoft Visual Studio Async CTP\Samples(C# Testing) Unit Testing\AsyncTestUtilities. Alternatively, you can use AsyncContext from my Nito.AsyncEx NuGet package. Here's an example using AsyncContext; GeneralThreadAffineContext has almost identical usage: using Nito.AsyncEx; class Program { static void Main(string[] args) { AsyncContext.Run(() => MainAsync(args)); } static async void MainAsync(string[] args) { Bootstrapper bs = new Bootstrapper(); var list = await bs.GetList(); } } Alternatively, you can just block the main Console thread until your asynchronous work has completed: class Program { static void Main(string[] args) { MainAsync(args).GetAwaiter().GetResult(); } static async Task MainAsync(string[] args) { Bootstrapper bs = new Bootstrapper(); var list = await bs.GetList(); } } Note the use of GetAwaiter().GetResult(); this avoids the AggregateException wrapping that happens if you use Wait() or Result.
You can solve this with this simple construct: class Program { static void Main(string[] args) { Task.Run(async () => { // Do any async anything you need here without worry }).GetAwaiter().GetResult(); } } That will put everything you do out on the ThreadPool where you'd want it (so other Tasks you start/await don't attempt to rejoin a Thread they shouldn't), and wait until everything's done before closing the Console app. No need for special loops or outside libs. Edit: Incorporate Andrew's solution for uncaught Exceptions.
You can do this without needing external libraries also by doing the following: class Program { static void Main(string[] args) { Bootstrapper bs = new Bootstrapper(); var getListTask = bs.GetList(); // returns the Task<List<TvChannel>> Task.WaitAll(getListTask); // block while the task completes var list = getListTask.Result; } }
In C# 7.1 you will be able to do a proper async Main. The appropriate signatures for Main method has been extended to: public static Task Main(); public static Task<int> Main(); public static Task Main(string[] args); public static Task<int> Main(string[] args); For e.g. you could be doing: static async Task Main(string[] args) { Bootstrapper bs = new Bootstrapper(); var list = await bs.GetList(); } At compile time, the async entry point method will be translated to call GetAwaitor().GetResult(). Details: https://blogs.msdn.microsoft.com/mazhou/2017/05/30/c-7-series-part-2-async-main EDIT: To enable C# 7.1 language features, you need to right-click on the project and click "Properties" then go to the "Build" tab. There, click the advanced button at the bottom: From the language version drop-down menu, select "7.1" (or any higher value): The default is "latest major version" which would evaluate (at the time of this writing) to C# 7.0, which does not support async main in console apps.
I'll add an important feature that all of the other answers have overlooked: cancellation. One of the big things in TPL is cancellation support, and console apps have a method of cancellation built in (CTRL+C). It's very simple to bind them together. This is how I structure all of my async console apps: static void Main(string[] args) { CancellationTokenSource cts = new CancellationTokenSource(); System.Console.CancelKeyPress += (s, e) => { e.Cancel = true; cts.Cancel(); }; MainAsync(args, cts.Token).GetAwaiter.GetResult(); } static async Task MainAsync(string[] args, CancellationToken token) { ... }
C# 7.1 (using vs 2017 update 3) introduces async main You can write: static async Task Main(string[] args) { await ... } For more details C# 7 Series, Part 2: Async Main Update: You may get a compilation error: Program does not contain a static 'Main' method suitable for an entry point This error is due to that vs2017.3 is configured by default as c#7.0 not c#7.1. You should explicitly modify the setting of your project to set c#7.1 features. You can set c#7.1 by two methods: Method 1: Using the project settings window: Open the settings of your project Select the Build tab Click the Advanced button Select the version you want As shown in the following figure: Method2: Modify PropertyGroup of .csproj manually Add this property: <LangVersion>7.1</LangVersion> example: <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PlatformTarget>AnyCPU</PlatformTarget> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> <OutputPath>bin\Debug\</OutputPath> <DefineConstants>DEBUG;TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> <Prefer32Bit>false</Prefer32Bit> <LangVersion>7.1</LangVersion> </PropertyGroup>
If you're using C# 7.1 or later, go with the nawfal's answer and just change the return type of your Main method to Task or Task<int>. If you are not: Have an async Task MainAsync like Johan said. Call its .GetAwaiter().GetResult() to catch the underlying exception like do0g said. Support cancellation like Cory said. A second CTRL+C should terminate the process immediately. (Thanks binki!) Handle OperationCancelledException - return an appropriate error code. The final code looks like: private static int Main(string[] args) { var cts = new CancellationTokenSource(); Console.CancelKeyPress += (s, e) => { e.Cancel = !cts.IsCancellationRequested; cts.Cancel(); }; try { return MainAsync(args, cts.Token).GetAwaiter().GetResult(); } catch (OperationCanceledException) { return 1223; // Cancelled. } } private static async Task<int> MainAsync(string[] args, CancellationToken cancellationToken) { // Your code... return await Task.FromResult(0); // Success. }
Haven't needed this much yet, but when I've used console application for Quick tests and required async I've just solved it like this: class Program { static void Main(string[] args) { MainAsync(args).Wait(); } static async Task MainAsync(string[] args) { // Code here } }
For asynchronously calling task from Main, use Task.Run() for .NET 4.5 Task.Factory.StartNew() for .NET 4.0 (May require Microsoft.Bcl.Async library for async and await keywords) Details: http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx
In Main try changing the call to GetList to: Task.Run(() => bs.GetList());
When the C# 5 CTP was introduced, you certainly could mark Main with async... although it was generally not a good idea to do so. I believe this was changed by the release of VS 2013 to become an error. Unless you've started any other foreground threads, your program will exit when Main completes, even if it's started some background work. What are you really trying to do? Note that your GetList() method really doesn't need to be async at the moment - it's adding an extra layer for no real reason. It's logically equivalent to (but more complicated than): public Task<List<TvChannel>> GetList() { return new GetPrograms().DownloadTvChannels(); }
Newest version of C# - C# 7.1 allows to create async console app. To enable C# 7.1 in project, you have to upgrade your VS to at least 15.3, and change C# version to C# 7.1 or C# latest minor version. To do this, go to Project properties -> Build -> Advanced -> Language version. After this, following code will work: internal class Program { public static async Task Main(string[] args) { (...) }
As of C# 7.1 the following signatures are valid for the Main method. public static void Main() { } public static int Main() { } public static void Main(string[] args) { } public static int Main(string[] args) { } public static async Task Main() { } public static async Task<int> Main() { } public static async Task Main(string[] args) { } public static async Task<int> Main(string[] args) { } So, now you can do async/await static async Task Main(string[] args) { Console.WriteLine("Hello Asyn Main method!"); await Task.Delay(200); }
On MSDN, the documentation for Task.Run Method (Action) provides this example which shows how to run a method asynchronously from main: using System; using System.Threading; using System.Threading.Tasks; public class Example { public static void Main() { ShowThreadInfo("Application"); var t = Task.Run(() => ShowThreadInfo("Task") ); t.Wait(); } static void ShowThreadInfo(String s) { Console.WriteLine("{0} Thread ID: {1}", s, Thread.CurrentThread.ManagedThreadId); } } // The example displays the following output: // Application thread ID: 1 // Task thread ID: 3 Note this statement that follows the example: The examples show that the asynchronous task executes on a different thread than the main application thread. So, if instead you want the task to run on the main application thread, see the answer by #StephenCleary. And regarding the thread on which the task runs, also note Stephen's comment on his answer: You can use a simple Wait or Result, and there's nothing wrong with that. But be aware that there are two important differences: 1) all async continuations run on the thread pool rather than the main thread, and 2) any exceptions are wrapped in an AggregateException. (See Exception Handling (Task Parallel Library) for how to incorporate exception handling to deal with an AggregateException.) Finally, on MSDN from the documentation for Task.Delay Method (TimeSpan), this example shows how to run an asynchronous task that returns a value: using System; using System.Threading.Tasks; public class Example { public static void Main() { var t = Task.Run(async delegate { await Task.Delay(TimeSpan.FromSeconds(1.5)); return 42; }); t.Wait(); Console.WriteLine("Task t Status: {0}, Result: {1}", t.Status, t.Result); } } // The example displays the following output: // Task t Status: RanToCompletion, Result: 42 Note that instead of passing a delegate to Task.Run, you can instead pass a lambda function like this: var t = Task.Run(async () => { await Task.Delay(TimeSpan.FromSeconds(1.5)); return 42; });
In my case I had a list of jobs that I wanted to run in async from my main method, have been using this in production for quite sometime and works fine. static void Main(string[] args) { Task.Run(async () => { await Task.WhenAll(jobslist.Select(nl => RunMulti(nl))); }).GetAwaiter().GetResult(); } private static async Task RunMulti(List<string> joblist) { await ... }
To avoid freezing when you call a function somewhere down the call stack that tries to re-join the current thread (which is stuck in a Wait), you need to do the following: class Program { static void Main(string[] args) { Bootstrapper bs = new Bootstrapper(); List<TvChannel> list = Task.Run((Func<Task<List<TvChannel>>>)bs.GetList).Result; } } (the cast is only required to resolve ambiguity)
class Program { public static EventHandler AsyncHandler; static void Main(string[] args) { AsyncHandler+= async (sender, eventArgs) => { await AsyncMain(); }; AsyncHandler?.Invoke(null, null); } private async Task AsyncMain() { //Your Async Code } }
This is hypothetical but I am thinking: static void Main(string[] args) { var context = new Thread(() => /*do stuff*/); context.Start(); context.Join(); }
Not sure if this is what you're looking for, but I wanted to await a method on load. I ended up using the Main_Shown handler and making it async: private async void Main_Shown(object sender, EventArgs e) { await myAsyncMethod(); }
The following code can be used to make a main async. I've tweak it to use long running tasks (learn more here: https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcreationoptions?view=net-7.0) It's also implementing the cancellation token from the above response. private static int Main(string[] args) { var cts = new CancellationTokenSource(); Console.CancelKeyPress += (s, e) => { e.Cancel = !cts.IsCancellationRequested; cts.Cancel(); Console.WriteLine("CancellationRequested"); }; try { var task = new Task<int>( () => MainAsync(args, cts.Token).GetAwaiter().GetResult(), cts.Token, TaskCreationOptions.LongRunning //https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcreationoptions?view=net-7.0 ); task.Start(); var exitCode = task.GetAwaiter().GetResult(); /*Or this.*/ //var exitCode = MainAsync(args, cts.Token).GetAwaiter().GetResult(); return exitCode;// MainAsync(args, cts.Token).GetAwaiter().GetResult(); } catch (OperationCanceledException ex) { Console.WriteLine(ex); return 1223; // Cancelled. } catch(Exception ex) { Console.WriteLine(ex); return -1; } } private static async Task<int> MainAsync(string[] args, CancellationToken cancellationToken) { await Something() return; } In the following example I wrote. You can play with maxDegreeOfParallelism & numberOfIteration to understand / see how the task are handle. Good statring point for learning TPL! private static async Task<int> MainAsync(string[] args, CancellationToken cancellationToken) { var infos = new ConcurrentBag<Info>(); var mySuperUselessService = new BigWorkload(); int numberOfSecond = 1; int numberOfIteration = 25; //Experiment with this int maxDegreeOfParallelism = 4; //Experiment with this var simulateWorkTime = TimeSpan.FromSeconds(numberOfSecond); var informations = Enumerable.Range(1, numberOfIteration) .Select(x => new Info() { Index = x }); var count = informations.Count(); var chunkNeeded = Math.Round(count / Convert.ToDecimal(maxDegreeOfParallelism), MidpointRounding.ToPositiveInfinity); var splashInfo = #$" Press CTRL + C to cancel. Processing {count} items, maxDegreeOfParallelism set to {maxDegreeOfParallelism}. But it will be bound by the core on the machine {Environment.ProcessorCount}. This operation should take ~{chunkNeeded * (numberOfSecond + 0.01m)}s And will be starting test in 2s "; Console.WriteLine(splashInfo); await Task.Delay(TimeSpan.FromSeconds(2)); var parralelOptions = new ParallelOptions() { MaxDegreeOfParallelism = maxDegreeOfParallelism, CancellationToken = cancellationToken}; var stopwatch = new Stopwatch(); stopwatch.Start(); var forLoopTask = Parallel.ForEachAsync(informations, parralelOptions, async (info, token) => { await mySuperUselessService.Simulate(simulateWorkTime, info); Console.WriteLine(info); infos.Add(info); }); await forLoopTask; stopwatch.Stop(); foreach (var grouped in infos.GroupBy(x => x.ManagedThreadId)) { Console.WriteLine($"ThreadId: {grouped.Key}"); foreach (var item in grouped) { Console.WriteLine($"\t Index: {item.Index} {item.TaskCurrentId}"); } } Console.WriteLine($"NumberOfThread: {infos.GroupBy(x => x.ManagedThreadId).Count()}"); Console.WriteLine($"Elasped: {stopwatch.ElapsedMilliseconds / 1000d}s"); Console.WriteLine(splashInfo); return 0; }
How to call on async Task function from Void class?
How to call on async Task function from Void class? Let's say I got this built up like this, I Want to call the methods in Run() in sync, but in the DoSomeStuffAsync and DoSomeStuffAsync 2 It requires await on some functions that has async awaitable functions. My Question is, how can I in DoTask1 e.g. make the task to run sync? Like now the tasks just starts it and it doesn't wait until it finish at all. static void Main(string[] args) { Run(); } public void Run() { DoTask1(); DoTask2(); } public void DoTask1() { var tasks = Task.Run(async () => { await DoSomeStuffAsync(); await DoSomeStuffAsync2(); }); Task.WaitAll(tasks); } public void DoTask2() { var tasks = Task.Run(async () => { await DoSomeStuffAsync(); await DoSomeStuffAsync2(); }); Task.WaitAll(tasks); } private async Task DoSomeStuffAsync(int daysBack) { try { var data= await GetData(); var objj = GenerateObjects(); await InsertToDb(objj )); } catch (Exception ex) { Console.WriteLine(ex.Message); } } private async Task DoSomeStuffAsync2(int daysBack) { try { var data= await GetOtherData(); var objj = GenerateObjects(); await InsertToDb(objj )); } catch (Exception ex) { Console.WriteLine(ex.Message); } }
The Console app static void Main() is calling on the Run() function. You have a couple of options. For both of the options below, you should first make your Run method properly asynchronous (i.e., async Task). If this is a .NET Core project, then option A is to make Main an async Task method. Then you can use async all the way. If not, then you can have a single blocking call. I recommend that this go into your Main method, as such: static void Main() { Run().GetAwaiter().GetResult(); }
Async void is a bad choice, generates compiler warnings, if an exception is uncaught there, your application is dead and you won’t probably have a proper call stack to debug with. But if you want, you already have the solution just call directly the async task method. And wrappe it in a exception catcher static void Main(string[] args) { Task callTask = Task.Run(() => Run()); callTask.Wait(); } public async Task Run() { await DoSomeStuffAsync(); }
Topshelf start stuck in infinite loop
I'm creating a message processor to take messages of a queue I have used topshelf for this and justgot some basic code for now. However my message processor is stuck in a loop and causing my topshelf service to not start. I thought if I returned and stored the task, this would not be the case class Program { static void Main(string[] args) { HostFactory.Run(configure => { configure.Service<WorkerService>(service => { service.ConstructUsing(() => new WorkerService()); service.WhenStarted(s => s.Start()); service.WhenStopped(s => s.Stop()); }); configure.RunAsLocalSystem(); }); } } public class WorkerService { private Task _task; private Processor _processor; private readonly CancellationTokenSource _cancellation; public WorkerService() { _cancellation = new CancellationTokenSource(); _processor = new Processor(); } public void Start() { Console.WriteLine("Starting"); _task = _processor.Run(_cancellation.Token); Console.WriteLine("I NEVER GET HERE"); } public void Stop() { _cancellation.Cancel(); _task.Wait(); } } public class Processor { public async Task Run(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { Console.WriteLine("Running"); } } } So when I look at my windows services I just see this app stuck in "Starting"
Your run function doesn't actually hit an await call (where it will exit and later resume). In fact, it doesn't exit at all. You're stuck in the Run method. Try putting this after your Console.WriteLine: await Task.Delay(200); In addition, you might consider not mixing async/await with traditional Task.Wait(), as that's known to cause deadlocks as well. Example: await vs Task.Wait - Deadlock?
Entity object inside Async and Await process
I'm trying to use Async and Await for upload process. I created a small code to see if it works. class Program { static void Main(string[] args) { for (int i = 0; i < 5; i++) { TestAsync().Wait(); } } public static async Task TestAsync() { await Task.Run(() => { Thread.Sleep(1000); var context = new CommonEntities(); context.AddToDummies(new Dummy { TimeStamp = DateTime.Now, Caption = "Async" }); context.SaveChanges(); }); } } But for some reason, it never gets to Console.WriteLine. If I replaced var context = new EntityObject(); with var stringBuilder = new StringBuilder(); then it worked. The idea is that I will create a method which has many complex procedures of saving and updating database as well as calling a webservice and store the result to database etc. Let say that method is called MethodA. public static async void test() { await Task.Run(() => MethodA()); } But before going further, I am stuck in this simple test. Any idea why that is?
You shouldn't be using async void anywhere other than an event handler. async void doesn't allow the caller to wait (asynchronously or otherwise) for the operation to complete, it just moves on. In your case it reaches the end of Main and the application ends before you get a chance to reach the Console.WriteLine. You need to change TestAsync to return a Task and wait for it in Main: static void Main() { TestAsync().Wait(); } public static async Task TestAsync() { await Task.Run(() => { var objectContext = new CommonEntities(); Console.WriteLine("Processed"); }); }
Async TPL deadlock with third party lib aka wild goose chase
After spending a very frustrating and unproductive day on this, I'm posting here in search of help. I am using a third-party library that initiates a network connection in an unknown manner (I do know however it's a managed wrapper for an unmanaged lib). It lets you know about the status of the connection by invoking an event StatusChanged(status). Since obviously invoking the network is costly and I may not need it for my Service, I inject an AsyncLazy<Connection> which is then invoked if necessary. The Service is accessed by ParallelForEachAsync which is an extension I made to process Tasks concurrently, based on this post. If accessed sequentially, all is well. Any concurrency, even 2 parallel tasks will result in a deadlock 90% of the time. I know it's definitely related to how the third-party lib interacts with my code because a) I am not able to reproduce the effect using the same structure but without invoking it and b) the event StatusChanged(Connecting) is received fine, at which point I assume the network operation is started and I never get a callback for StatusChanged(Connected). Here's a as-faithful-as-possible repro of the code structure which doesn't reproduce the deadlock unfortunately. Any ideas on how to go about resolving this? class Program { static void Main(string[] args) { AsyncContext.Run(() => MainAsync(args)); } static async Task MainAsync(string[] args) { var lazy = new AsyncLazy<Connection>(() => ConnectionFactory.Create()); var service = new Service(lazy); await Enumerable.Range(0, 100) .ParallelForEachAsync(10, async i => { await service.DoWork(); Console.WriteLine("did some work"); }, CancellationToken.None); } } class ConnectionFactory { public static Task<Connection> Create() { var tcs = new TaskCompletionSource<Connection>(); var session = new Session(); session.Connected += (sender, args) => { Console.WriteLine("connected"); tcs.SetResult(new Connection()); }; session.Connect(); return tcs.Task; } } class Connection { public async Task DoSomethinElse() { await Task.Delay(1000); } } class Session { public event EventHandler Connected; public void Connect() { Console.WriteLine("Simulate network operation with unknown scheduling"); Task.Delay(100).Wait(); Connected(this, EventArgs.Empty); } } class Service { private static Random r = new Random(); private readonly AsyncLazy<Connection> lazy; public Service(AsyncLazy<Connection> lazy) { this.lazy = lazy; } public async Task DoWork() { Console.WriteLine("Trying to do some work, will connect"); await Task.Delay(r.Next(0, 100)); var connection = await lazy; await connection.DoSomethinElse(); } } public static class AsyncExtensions { public static async Task<AsyncParallelLoopResult> ParallelForEachAsync<T>( this IEnumerable<T> source, int degreeOfParallelism, Func<T, Task> body, CancellationToken cancellationToken) { var partitions = Partitioner.Create(source).GetPartitions(degreeOfParallelism); bool wasBroken = false; var tasks = from partition in partitions select Task.Run(async () => { using (partition) { while (partition.MoveNext()) { if (cancellationToken.IsCancellationRequested) { Volatile.Write(ref wasBroken, true); break; } await body(partition.Current); } } }); await Task.WhenAll(tasks) .ConfigureAwait(false); return new AsyncParallelLoopResult(Volatile.Read(ref wasBroken)); } } public class AsyncParallelLoopResult { public bool IsCompleted { get; private set; } internal AsyncParallelLoopResult(bool isCompleted) { IsCompleted = isCompleted; } } EDIT I think I understand why it's happening but not sure how to solve it. While the context is waiting for DoWork, DoWork is waiting for the lazy connection. This ugly hack seems to solve it: Connection WaitForConnection() { connectionLazy.Start(); var awaiter = connectionLazy.GetAwaiter(); while (!awaiter.IsCompleted) Thread.Sleep(50); return awaiter.GetResult(); } Any more elegant solutions?
I suspect that the 3rd-party library is requiring some kind of STA pumping. This is fairly common with old-style asynchronous code. I have a type AsyncContextThread that you can try, passing true to the constructor to enable manual STA pumping. AsyncContextThread is just like AsyncContext except it runs the context within a new thread (an STA thread in this case). static void Main(string[] args) { using (var thread = new AsyncContextThread(true)) { thread.Factory.Run(() => MainAsync(args)).Wait(); } } or static void Main(string[] args) { AsyncContext.Run(() => async { using (var thread = new AsyncContextThread(true)) { await thread.Factory.Run(() => MainAsync(args)); } } } Note that AsyncContextThread will not work in all STA scenarios. I have run into issues when doing (some rather twisted) COM interop that required a true UI thread (WPF or WinForms thread); for some reason the STA pumping wasn't sufficient for those COM objects.