-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Async Main [Speclet] #7476
Comments
CC @dotnet/roslyn-compiler |
This would be a breaking change. The following program produces only a warning today, but it would be an error under this proposal. using System.Threading.Tasks;
namespace CSharpSample1
{
class Program
{
static int Main(string[] args)
{
return Main().GetAwaiter().GetResult();
}
static Task<int> Main()
{
throw null;
}
}
} |
@gafter: Looks like that's correct. There's three options that I can see:
Obviously, I'd prefer option 2 (unless there are any other cleaner solutions). Right now we fail with an error if there are more than one "viable" entry point methods. Going with option two means that we would introduce preference. Not something to take lightly, but maybe worth it in this scenario? Most people that hit this edge case would likely want to use this feature. Update: we are going with option two, I'll update the speclet. |
Yes, I think option (2) makes sense. Formally, we would say that a method with one of the And we should check with the whole LDM to make sure we have consensus on this (or some other) approach. /cc @MadsTorgersen |
/cc @stephentoub As the champion for this feature, how do you suggest we handle this? |
@gafter I have updated the Detailed Design section of the speclet to include the resolution to your example program. |
A small clarification:
No, it wouldn't ignore them, calling |
@svick: thanks for the feedback, I've updated that section. |
What about including a SynchronizationContext? One thing I like about async is that you have much less worries about race conditions, as everything in an async flow happens in a specific thread/sync context.
Would it be possible to include a similar class in coreclr/corefx that takes care of setting up a proper sync context, and using it in the generated Main()? |
Here's an example: http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx |
This is something that would certainly be nice to have, but is out of scope of this speclet. Also, I don't see how you would go about adding synchronization contexts to the proposed syntax. |
Point of order: Why is this a separate issue from #1695? The speclet seems largely a duplicate (though with a few additional points) of my comments from #1695 (comment). Regardless...
I'm fine with the approach: "Yes, I think option (2) makes sense. Formally, we would say that a method with one of the Task return types is not a candidate to be a "main method" unless there is no candidate under the old rules."
As I noted in #1695, I do not believe the language feature should do anything with regards to synchronization context, in particular because a) that brings a ton of policy into the language, and b) there are many variations on what that policy could be. If a developer wants to layer on that support, they can do so manually. There's a separate question (unrelated to Roslyn) of whether corefx should provide any additional types to help with such an implementation, noting that it already provides types that would enable serialized execution, e.g. ConcurrentExclusiveSchedulerPair. |
I wanted to collect all the information about the feature in one spot so it could be easily reviewed by the LDM. |
The method should be named This way, we only leave open if it should be the runtime to also look for
For such small programs, if you have both synchronous and asynchronous APIs available, the asynchronous ones will only generate overhead. If you only have asynchronous APIs, you only save 1 to 4 lines of code:
For not so small programs, this should be the least of your troubles.
Really?
What's the big deal? There's no requirement that the host handles specific exceptions differently, or that it outputs the thrown exception at all, much less that it formats the exception and inner exceptions in a certain way. If you care, you should seriously log and/or handle exceptions, either with language constructs ( I prefer
I honestly expect anyone to notice this during development.
I agree. Also, see my first reply regarding the asynchronous entry point method's name.
Actually, I don't really understand the issue here. There will always be a sync-to-async transition, whether you see it or not. In your opinion, on what methods would
I agree. This consistency is probably the only reasonable argument. However, it's not a substantial saving.
But it will block You just don't see it. We should probably skip this. Asynchronous code should not be taken so lightly. At any point, at least one non-background thread must be alive to keep the program running. You should make sure how this is implemented yourself. And if you do, you can make interesting things like creating a In case this goes forward, do the |
In addition: possible, it is better to use main thread in thread pool for this case? So we will not have "sleeping" thread. |
We are now tracking this proposal at dotnet/csharplang#97. It is championed by @stephentoub . |
Async Main
Summary
Allow Main methods to be marked
async
, allowing the use ofawait
inside of them.Motivation
Many programs (especially small ones) are written in a way that is almost entirely asynchronous. However, currently, programmers need to manually create a bridge between synchronous code
(starting at Main because Main is required to be synchronous), and the deeper levels of their application code (which might be using async APIs). That is to say, their code must -- at some level -- block while waiting for a result in order to go from being asynchronous to synchronous.
There are a subset of programs that contain this bridge inside the Main method itself.
Doing this by hand is a waste of time and can be a cause of bugs. In the above example, writing
DoWork().Wait()
would wrap any thrown exceptions in an AggregateException. WritingDoWork()
with no Wait or GetResult may result in the program shutting down before execution of the asynchronous task is finished.Instead of making the user hand-write this transfer, we would like to have the compiler do this bridging manually by allowing main methods to be marked as
async
.Detailed Design
The following signatures are currently invalid entrypoints, but would become valid if this speclet were to be implemented.
Because the CLR doesn't accept async methods as entrypoints, the C# compiler would generate a synthesized
main method calls the user-defined async Main.
Task
, a synthesizedstatic void Main
is generated.Task<int>
, a synthesizedstatic int Main
is generated.array as well; passing it on to the user-defined async Main.
The body of the synthesized Main method contains a call to the user-defined async Main on the receiving end of
.GetAwaiter().GetResult()
.An example transformation is provided below.
There is one back-compat issue that we need to worry about. As @gafter showed in his example, old code using traditional Main alongside a new async Main will be problematic. Previously, his code would produce warnings, but with async Main being a valid entrypoint, there would be more than one valid entrypoint found, resulting in an error.
The proposed solution to this would be that the compiler only looks for an async Main after not finding any synchronous Mains. If a synchronous Main is found, then warnings are issued for any async Main that is found afterward.
Drawbacks
async Main
might encourage inexperienced programmers to try to use async onmore methods than are necessary, because they don't need to think about the transition from sync to async
anymore.
Benefits
await
in their "main" context)that it's done correctly.
API Impact
When a compilation is asked for viable entrypoints, any user-defined async Main methods will be returned. The synthesized "real" entry point will be invisible.
Unresolved Questions
async void Main
? If so, what would the synthesized version do?The text was updated successfully, but these errors were encountered: