Skip to content

.NET 9 Runtime Async Experiment #94620

Closed
Closed
@agocke

Description

@agocke

Update:

We've now completed the initial experiment into runtime-async. Overall, the experiment was very successful. For details, see https://github.com/dotnet/runtimelab/blob/feature/async2-experiment/docs/design/features/runtime-handled-tasks.md. We tested two possible implementations: a VM implementation and a JIT implementation. Of the two, we are more positive about the JIT implementation, both for performance and for maintenance.

Our primary conclusion is that runtime-async is at least as good as compiler-async in all the configurations that we measured. In addition, we believe that the new implementation can be fully compatible with the existing compiler-async, meaning that runtime-async can be a drop-in replacement.

We would like to graduate this experiment to a new runtime feature. However, this is a large feature which may take multiple releases to complete. In order to transparently replace the compiler-async implementation we will have to implement all the existing functionality in runtime-async.

For now we'll close out the experiment with the detailed results listed in the link above, and plan to publish more information on runtime-async planning as things become more concrete.


Intro

In .NET 8 we started an experiment in adding support for green threads to .NET. We learned a lot, but decided not to continue at the current time.

In .NET 9 we'd like to take what we learned and explore performance and usability improvements of the existing .NET async/Task threading model.

Background

From the C# and .NET libraries level, there are two supporting threading models: OS threads, and C# async/Task. Concurrent code can access each of these models using the System.Threading.Thread type or C# async/Task.Run, respectively. For most modern C# code we recommend using async and Task if you need blocking-free waiting or concurrency.

The Experiment

The status and code for the in-progress experiment can be found here: https://github.com/dotnet/runtimelab/tree/feature/async2-experiment

An ongoing design doc is present in: https://github.com/dotnet/runtimelab/blob/feature/async2-experiment/docs/design/features/runtime-handled-tasks.md

While async and Task are the newest and most-preferred option at the C# and .NET libraries level, they are not a direct part of the .NET runtime threading model.

This experiment asks the question: what if they were? Rather than implement the async structure entirely in C# as a state machine rewrite, we are interested in exploring direct runtime integration with async methods.

The characteristics we're interested in for this experiment are:

  • Throughput

    • Microbenchmarks -- how much does await cost?

    • Lots of nested awaits?

    • Frequent suspension vs. rare suspension

  • Compatibility

    • Are the semantics similar/identical to C#?

    • Cost of switching

  • Code size

    • IL size

    • Crossgen/Native AOT code size

As we explore more we might find more questions. At the moment, we're not planning to investigate things which require a lot of additional implementation work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    User StoryA single user-facing feature. Can be grouped under an epic.area-VM-coreclr

    Type

    No type

    Projects

    Status

    No status

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions