Support async expressions#362
Conversation
|
The chosen "language" for async support in the DLR is .NET types and interfaces. This is different that the current async support in IronPython, which emulates CPython and uses Python's types. I think that staying close to .NET is true to the spirit to the IRON languages and allows for seamless integration with the rest of the .NET ecosystem. Therefore the resulting type of an async expression in the DLR is simply The proposed async expression reuses the existing generator expression functionality in the DLR to slice the expression at the await points (by turning them to yield points, invisible to the caller). This is a convenience of reuse; both generators and async expressions are basically state machines, or coroutines, so it is possible to factor it out to better named methods/types. I don't know though if this would be useful. It will be interesting to look into async generators that combine both these concepts in one expression body. .NET (but not .NET Framework) has interface |
slozier
left a comment
There was a problem hiding this comment.
Apologies if this seems like a superficial review, most expression stuff is beyond me. 😄 Didn't spot anything that seemed obviously wrong.
| /// </summary> | ||
| internal sealed class AsyncRewriter { | ||
| private static readonly MethodInfo s_driveMethod | ||
| = typeof(Microsoft.Scripting.Runtime.AsyncHelpers).GetMethod("DriveAsync")!; |
There was a problem hiding this comment.
Would use nameof(Microsoft.Scripting.Runtime.AsyncHelpers.DriveAsync)`. Makes it easier to find usage.
There was a problem hiding this comment.
Yes. I thought that ObsoleteAttribute would cause it being an error, but it doesn't.
| Name = name; | ||
| Body = body; | ||
| YieldLabel = yieldLabel; | ||
| CancellationToken = cancellationToken ?? Expression.Default(typeof(CancellationToken)); |
There was a problem hiding this comment.
Guess it doesn't matter either way (just noting the difference), but in AsyncExpression you defined DefaultCancellationToken and DefaultCancellationException.
There was a problem hiding this comment.
Good catch, I didn't notice it. I prefer the reusable statics, since it is slightly better performance at a minuscule startup cost and this is the style many IronPython expressions employ. To keep it DRY and not to incur more startup cost than necessary, I moved it to Utils. Also some more shared stuff, keeping all that internal.
|
Thanks for the review. The real party will begin in IronPython, where I am trying to marry the .NET async push model with Python's async pull model. 😃 I guess I wanted you to comment on the addition to the public API of the DLR here. Are you OK with this? I wanted it to be stable (though it does warrant a minor version increase) and was careful with defining the public additions. I believe they are sufficient for IronPython's needs (despite the model differences), hence they will be stable, but we will know for sure only when the whole Another thing is that the async generator expressions in the DLR are .NET only. This is because Finally, there is still this use of generator expressions as a convenient way to drive async expressions. I wasn't satisfied with this, but with async generator expressions it actually worked out quite well. Also I don't quite know how to have async expressions fully in the push model, short of reimplementing the Roslyn's async state machine, which I for sure will newer do. It becomes more interesting and doable in .NET 11, but we are not there yet. First, .NET 10 has to become EOS, and even then, there is still .NET Framework. |
|
I'm fine with the new public APIs. They seem to follow the same pattern as other Edit: As for the |
Since a few months, IronPython has support of async functions, but it is fully implemented using the existing functionality of Python generators. This PR brings the support of async expressions directly into the DLR, so that any IRON language (not just IronPython) can easily have async/await. The actual await mechanism is delegated to the Roslyn-generated state machine, or (starting from .NET 11) to the CLR's runtime-async support. This scheme benefits from any optimizations done for Roslyn and/or CoreCLR.
I do have an IronPython implementation locally that uses it and is an alternative of the existing implementation of PEP 492. It is a great way of testing the code in the DLR. I think the added API of the DLR is now stable, perhaps even the implementation; I will see it when the IronPython side gets stable and complete enough, so it is possible some tweaks on the DLR side may still become necessary.